home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / share / system-config-printer / system-config-printer.py < prev    next >
Text File  |  2009-10-19  |  284KB  |  6,945 lines

  1. #!/usr/bin/env python
  2.  
  3. ## system-config-printer
  4.  
  5. ## Copyright (C) 2006, 2007, 2008, 2009 Red Hat, Inc.
  6. ## Copyright (C) 2006, 2007, 2008, 2009 Tim Waugh <twaugh@redhat.com>
  7. ## Copyright (C) 2006, 2007 Florian Festi <ffesti@redhat.com>
  8.  
  9. ## This program is free software; you can redistribute it and/or modify
  10. ## it under the terms of the GNU General Public License as published by
  11. ## the Free Software Foundation; either version 2 of the License, or
  12. ## (at your option) any later version.
  13.  
  14. ## This program is distributed in the hope that it will be useful,
  15. ## but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17. ## GNU General Public License for more details.
  18.  
  19. ## You should have received a copy of the GNU General Public License
  20. ## along with this program; if not, write to the Free Software
  21. ## Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22.  
  23. # config is generated from config.py.in by configure
  24. import config
  25.  
  26. import errno
  27. import sys, os, tempfile, time, traceback, re, httplib, glob
  28. import subprocess
  29. import signal, thread
  30. from timedops import *
  31. import dbus
  32. try:
  33.     import gtk.glade
  34. except RuntimeError, e:
  35.     print "system-config-printer:", e
  36.     print "This is a graphical application and requires DISPLAY to be set."
  37.     sys.exit (1)
  38.  
  39. import glib
  40. def show_uri (uri):
  41.     gtk.show_uri (gtk.gdk.screen_get_default (),
  42.                   uri,
  43.                   gtk.get_current_event_time ())
  44.  
  45. gtk.about_dialog_set_url_hook (lambda x, y: show_uri (y))
  46. gtk.about_dialog_set_email_hook (lambda x, y: show_uri ("mailto:" + y))
  47.  
  48. def show_help():
  49.     print ("\nThis is system-config-printer, " \
  50.            "a CUPS server configuration program.\n\n"
  51.            "Options:\n\n"
  52.            "  --setup-printer URI\n"
  53.            "            Select the (detected) CUPS device URI on start-up,\n"
  54.            "            and run the new-printer wizard for it.\n\n"
  55.            "  --configure-printer NAME\n"
  56.            "            Select the named printer on start-up, and open its\n"
  57.            "            properties dialog.\n\n"
  58.            "  --choose-driver NAME\n"
  59.            "            Select the named printer on start-up, and display\n"
  60.            "            the list of drivers.\n\n"
  61.            "  --print-test-page NAME\n"
  62.            "            Select the named printer on start-up and print a\n"
  63.            "            test page to it.\n\n"
  64.            "  --no-focus-on-map\n"
  65.            "            Do not focus the main window, to prevent focus \n"
  66.            "            stealing\n\n"
  67.            "  --debug   Enable debugging output.\n")
  68.  
  69. if len(sys.argv)>1 and sys.argv[1] == '--help':
  70.     show_help ()
  71.     sys.exit (0)
  72.  
  73. import cups
  74. cups.require ("1.9.42")
  75.  
  76. try:
  77.     cups.ppdSetConformance (cups.PPD_CONFORM_RELAXED)
  78. except AttributeError:
  79.     # Requires pycups 1.9.46
  80.     pass
  81.  
  82. try:
  83.     import pysmb
  84.     PYSMB_AVAILABLE=True
  85. except:
  86.     PYSMB_AVAILABLE=False
  87.  
  88. import cupshelpers, options
  89. import gobject # for TYPE_STRING and TYPE_PYOBJECT
  90. from glade import GtkGUI
  91. from optionwidgets import OptionWidget
  92. from debug import *
  93. import probe_printer
  94. import gtk_label_autowrap
  95. import urllib
  96. import troubleshoot
  97. import jobviewer
  98. import authconn
  99. import monitor
  100. from smburi import SMBURI
  101. import errordialogs
  102. from errordialogs import *
  103. import installpackage
  104. import userdefault
  105. from AdvancedServerSettings import AdvancedServerSettingsDialog
  106. from PhysicalDevice import PhysicalDevice
  107. from ToolbarSearchEntry import *
  108. from GroupsPane import *
  109. from GroupsPaneModel import *
  110. from SearchCriterion import *
  111. import gtkinklevel
  112. import gtkspinner
  113. import statereason
  114.  
  115. domain='system-config-printer'
  116. import locale
  117. try:
  118.     locale.setlocale (locale.LC_ALL, "")
  119. except locale.Error:
  120.     os.environ['LC_ALL'] = 'C'
  121.     locale.setlocale (locale.LC_ALL, "")
  122. from gettext import gettext as _
  123. monitor.set_gettext_function (_)
  124. errordialogs.set_gettext_function (_)
  125. authconn.set_gettext_function (_)
  126. import gettext
  127. gettext.textdomain (domain)
  128. gettext.bindtextdomain (domain, config.localedir)
  129. gtk.glade.textdomain (domain)
  130. gtk.glade.bindtextdomain (domain, config.localedir)
  131. import ppdippstr
  132. pkgdata = config.pkgdatadir
  133. iconpath = os.path.join (pkgdata, 'icons/')
  134. sys.path.append (pkgdata)
  135.  
  136. busy_cursor = gtk.gdk.Cursor(gtk.gdk.WATCH)
  137.  
  138. TEXT_start_firewall_tool = _("To do this, select "
  139.                              "System->Administration->Firewall "
  140.                              "from the main menu.")
  141.  
  142. try:
  143.     try_CUPS_SERVER_REMOTE_ANY = cups.CUPS_SERVER_REMOTE_ANY
  144. except AttributeError:
  145.     # cups module was compiled with CUPS < 1.3
  146.     try_CUPS_SERVER_REMOTE_ANY = "_remote_any"
  147.  
  148. def validDeviceURI (uri):
  149.     """Returns True is the provided URI is valid."""
  150.     (scheme, rest) = urllib.splittype (uri)
  151.     if scheme == None or scheme == '':
  152.         return False
  153.     return True
  154.  
  155. def CUPS_server_hostname ():
  156.     host = cups.getServer ()
  157.     if host[0] == '/':
  158.         return 'localhost'
  159.     return host
  160.  
  161. # Both the printer properties window and the new printer window
  162. # need to be able to drive 'class members' selections.
  163. def moveClassMembers(treeview_from, treeview_to):
  164.     selection = treeview_from.get_selection()
  165.     model_from, rows = selection.get_selected_rows()
  166.     rows = [gtk.TreeRowReference(model_from, row) for row in rows]
  167.  
  168.     model_to = treeview_to.get_model()
  169.  
  170.     for row in rows:
  171.         path = row.get_path()
  172.         iter = model_from.get_iter(path)
  173.         row_data = model_from.get(iter, 0)
  174.         model_to.append(row_data)
  175.         model_from.remove(iter)
  176.  
  177. def getCurrentClassMembers(treeview):
  178.     model = treeview.get_model()
  179.     iter = model.get_iter_root()
  180.     result = []
  181.     while iter:
  182.         result.append(model.get(iter, 0)[0])
  183.         iter = model.iter_next(iter)
  184.     result.sort()
  185.     return result
  186.  
  187. def on_delete_just_hide (widget, event):
  188.     widget.hide ()
  189.     return True # stop other handlers
  190.  
  191. class GUI(GtkGUI, monitor.Watcher):
  192.  
  193.     printer_states = { cups.IPP_PRINTER_IDLE: _("Idle"),
  194.                        cups.IPP_PRINTER_PROCESSING: _("Processing"),
  195.                        cups.IPP_PRINTER_BUSY: _("Busy"),
  196.                        cups.IPP_PRINTER_STOPPED: _("Stopped") }
  197.  
  198.     def __init__(self, setup_printer = None, configure_printer = None,
  199.                  change_ppd = False, devid = "", print_test_page = False,
  200.                  focus_on_map = True):
  201.  
  202.         try:
  203.             self.language = locale.getlocale(locale.LC_MESSAGES)
  204.             self.encoding = locale.getlocale(locale.LC_CTYPE)
  205.         except:
  206.             nonfatalException()
  207.             os.environ['LC_ALL'] = 'C'
  208.             locale.setlocale (locale.LC_ALL, "")
  209.             self.language = locale.getlocale(locale.LC_MESSAGES)
  210.             self.encoding = locale.getlocale(locale.LC_CTYPE)
  211.  
  212.         self.printer = None
  213.         self.conflicts = set() # of options
  214.         self.connect_server = (self.printer and self.printer.getServer()) \
  215.                                or cups.getServer()
  216.         self.connect_encrypt = cups.getEncryption ()
  217.         self.connect_user = cups.getUser()
  218.  
  219.         self.changed = set() # of options
  220.  
  221.         self.servers = set((self.connect_server,))
  222.         self.server_is_publishing = False
  223.         self.devid = devid
  224.         self.focus_on_map = focus_on_map
  225.  
  226.         # WIDGETS
  227.         # =======
  228.         self.updating_widgets = False
  229.         self.getWidgets({"PrintersWindow":
  230.                              ["PrintersWindow",
  231.                               "view_area_vbox",
  232.                               "view_area_scrolledwindow",
  233.                               "dests_iconview",
  234.                               "statusbarMain",
  235.                               "toolbar",
  236.                               "server_settings_menu_entry",
  237.                               "new_printer",
  238.                               "new_class",
  239.                               "group_menubar_item",
  240.                               "printer_menubar_item",
  241.                               "view_discovered_printers",
  242.                               "view_groups"],
  243.                          "AboutDialog":
  244.                              ["AboutDialog"],
  245.                          "ConnectDialog":
  246.                              ["ConnectDialog",
  247.                               "chkEncrypted",
  248.                               "cmbServername",
  249.                               "btnConnect"],
  250.                          "ConnectingDialog":
  251.                              ["ConnectingDialog",
  252.                               "lblConnecting",
  253.                               "pbarConnecting"],
  254.                          "NewPrinterName":
  255.                              ["NewPrinterName",
  256.                               "entCopyName",
  257.                               "btnCopyOk"],
  258.                          "ServerSettingsDialog":
  259.                              ["ServerSettingsDialog",
  260.                               "chkServerBrowse",
  261.                               "chkServerShare",
  262.                               "chkServerShareAny",
  263.                               "chkServerRemoteAdmin",
  264.                               "chkServerAllowCancelAll",
  265.                               "chkServerLogDebug",
  266.                               "hboxServerBrowse"],
  267.                          "PrinterPropertiesDialog":
  268.                              ["PrinterPropertiesDialog",
  269.                               "tvPrinterProperties",
  270.                               "btnPrinterPropertiesCancel",
  271.                               "btnPrinterPropertiesOK",
  272.                               "btnPrinterPropertiesApply",
  273.                               "btnPrinterPropertiesClose",
  274.                               "ntbkPrinter",
  275.                               "entPDescription",
  276.                               "entPLocation",
  277.                               "lblPMakeModel",
  278.                               "lblPMakeModel2",
  279.                               "lblPState",
  280.                               "entPDevice",
  281.                               "lblPDevice2",
  282.                               "btnSelectDevice",
  283.                               "btnChangePPD",
  284.                               "chkPEnabled",
  285.                               "chkPAccepting",
  286.                               "chkPShared",
  287.                               "lblNotPublished",
  288.                               "btnPrintTestPage",
  289.                               "btnSelfTest",
  290.                               "btnCleanHeads",
  291.                               "btnConflict",
  292.  
  293.                               "cmbPStartBanner",
  294.                               "cmbPEndBanner",
  295.                               "cmbPErrorPolicy",
  296.                               "cmbPOperationPolicy",
  297.  
  298.                               "rbtnPAllow",
  299.                               "rbtnPDeny",
  300.                               "tvPUsers",
  301.                               "entPUser",
  302.                               "btnPAddUser",
  303.                               "btnPDelUser",
  304.  
  305.                               "lblPInstallOptions",
  306.                               "swPInstallOptions",
  307.                               "vbPInstallOptions",
  308.                               "swPOptions",
  309.                               "lblPOptions",
  310.                               "vbPOptions",
  311.                               "algnClassMembers",
  312.                               "vbClassMembers",
  313.                               "lblClassMembers",
  314.                               "tvClassMembers",
  315.                               "tvClassNotMembers",
  316.                               "btnClassAddMember",
  317.                               "btnClassDelMember",
  318.                               "btnRefreshMarkerLevels",
  319.                               "tvPrinterStateReasons",
  320.                               "ntbkPrinterStateReasons",
  321.  
  322.                               # Job options
  323.                               "sbJOCopies", "btnJOResetCopies",
  324.                               "cmbJOOrientationRequested", "btnJOResetOrientationRequested",
  325.                               "cbJOFitplot", "btnJOResetFitplot",
  326.                               "cmbJONumberUp", "btnJOResetNumberUp",
  327.                               "cmbJONumberUpLayout", "btnJOResetNumberUpLayout",
  328.                               "sbJOBrightness", "btnJOResetBrightness",
  329.                               "cmbJOFinishings", "btnJOResetFinishings",
  330.                               "sbJOJobPriority", "btnJOResetJobPriority",
  331.                               "cmbJOMedia", "btnJOResetMedia",
  332.                               "cmbJOSides", "btnJOResetSides",
  333.                               "cmbJOHoldUntil", "btnJOResetHoldUntil",
  334.                               "cbJOMirror", "btnJOResetMirror",
  335.                               "sbJOScaling", "btnJOResetScaling",
  336.                               "sbJOSaturation", "btnJOResetSaturation",
  337.                               "sbJOHue", "btnJOResetHue",
  338.                               "sbJOGamma", "btnJOResetGamma",
  339.                               "sbJOCpi", "btnJOResetCpi",
  340.                               "sbJOLpi", "btnJOResetLpi",
  341.                               "sbJOPageLeft", "btnJOResetPageLeft",
  342.                               "sbJOPageRight", "btnJOResetPageRight",
  343.                               "sbJOPageTop", "btnJOResetPageTop",
  344.                               "sbJOPageBottom", "btnJOResetPageBottom",
  345.                               "cbJOPrettyPrint", "btnJOResetPrettyPrint",
  346.                               "cbJOWrap", "btnJOResetWrap",
  347.                               "sbJOColumns", "btnJOResetColumns",
  348.                               "tblJOOther",
  349.                               "entNewJobOption", "btnNewJobOption",
  350.  
  351.                               # Marker levels
  352.                               "vboxMarkerLevels",
  353.                               "btnRefreshMarkerLevels"]})
  354.  
  355.  
  356.         # Ensure the default PrintersWindow is shown despite
  357.         # the --no-focus-on-map option
  358.         self.PrintersWindow.set_focus_on_map (self.focus_on_map)
  359.  
  360.         # Since some dialogs are reused we can't let the delete-event's
  361.         # default handler destroy them
  362.         for dialog in [self.PrinterPropertiesDialog,
  363.                        self.ServerSettingsDialog]:
  364.             dialog.connect ("delete-event", on_delete_just_hide)
  365.  
  366.         self.ConnectingDialog.connect ("delete-event",
  367.                                        self.on_connectingdialog_delete)
  368.  
  369.         gtk.window_set_default_icon_name ('printer')
  370.  
  371.         # Toolbar
  372.         # Glade-2 doesn't have support for MenuToolButton, so we do that here.
  373.         self.btnNew = gtk.MenuToolButton ('gtk-new')
  374.         self.btnNew.set_is_important (True)
  375.         newmenu = gtk.Menu ()
  376.         newprinter = gtk.ImageMenuItem (_("Printer"))
  377.         printericon = gtk.Image ()
  378.         printericon.set_from_icon_name ("printer", gtk.ICON_SIZE_MENU)
  379.         newprinter.set_image (printericon)
  380.         newprinter.connect ('activate', self.on_new_printer_activate)
  381.         self.btnNew.connect ('clicked', self.on_new_printer_activate)
  382.         newclass = gtk.ImageMenuItem (_("Class"))
  383.         classicon = gtk.Image ()
  384.         classicon.set_from_icon_name ("gtk-dnd-multiple", gtk.ICON_SIZE_MENU)
  385.         newclass.set_image (classicon)
  386.         newclass.connect ('activate', self.on_new_class_activate)
  387.         newprinter.show ()
  388.         newclass.show ()
  389.         newmenu.attach (newprinter, 0, 1, 0, 1)
  390.         newmenu.attach (newclass, 0, 1, 1, 2)
  391.         self.btnNew.set_menu (newmenu)
  392.         self.toolbar.add (self.btnNew)
  393.         self.toolbar.add (gtk.SeparatorToolItem ())
  394.         refreshbutton = gtk.ToolButton ('gtk-refresh')
  395.         refreshbutton.connect ('clicked', self.on_btnRefresh_clicked)
  396.         self.toolbar.add (refreshbutton)
  397.         self.toolbar.show_all ()
  398.  
  399.         # Printer Actions
  400.         printer_manager_action_group = \
  401.             gtk.ActionGroup ("PrinterManagerActionGroup")
  402.         printer_manager_action_group.add_actions ([
  403.                 ("rename-printer", None, _("_Rename"),
  404.                  None, None, self.on_rename_activate),
  405.                 ("copy-printer", gtk.STOCK_COPY, None,
  406.                  "<Ctrl>c", None, self.on_copy_activate),
  407.                 ("delete-printer", gtk.STOCK_DELETE, None,
  408.                  None, None, self.on_delete_activate),
  409.                 ("set-default-printer", gtk.STOCK_HOME, _("Set As De_fault"),
  410.                  None, None, self.on_set_as_default_activate),
  411.                 ("edit-printer", gtk.STOCK_PROPERTIES, None,
  412.                  None, None, self.on_edit_activate),
  413.                 ("create-class", gtk.STOCK_DND_MULTIPLE, _("_Create class"),
  414.                  None, None, self.on_create_class_activate),
  415.                 ("view-print-queue", gtk.STOCK_FIND, _("View Print _Queue"),
  416.                  None, None, self.on_view_print_queue_activate),
  417.                 ("add-to-group", None, _("_Add to Group"),
  418.                  None, None, None),
  419.                 ("save-as-group", None, _("Save Results as _Group"),
  420.                  None, None, self.on_save_as_group_activate),
  421.                 ("save-as-search-group", None, _("Save Filter as _Search Group"),
  422.                  None, None, self.on_save_as_search_group_activate),
  423.                 ])
  424.         printer_manager_action_group.add_toggle_actions ([
  425.                 ("enable-printer", None, _("E_nabled"),
  426.                  None, None, self.on_enabled_activate),
  427.                 ("share-printer", None, _("_Shared"),
  428.                  None, None, self.on_shared_activate),
  429.                 ])
  430.         printer_manager_action_group.add_radio_actions ([
  431.                 ("filter-name", None, _("Name")),
  432.                 ("filter-description", None, _("Description")),
  433.                 ("filter-location", None, _("Location")),
  434.                 ("filter-manufacturer", None, _("Manufacturer / Model")),
  435.                 ], 1, self.on_filter_criterion_changed)
  436.         for action in printer_manager_action_group.list_actions ():
  437.             action.set_sensitive (False)
  438.         printer_manager_action_group.get_action ("view-print-queue").set_sensitive (True)
  439.         printer_manager_action_group.get_action ("filter-name").set_sensitive (True)
  440.         printer_manager_action_group.get_action ("filter-description").set_sensitive (True)
  441.         printer_manager_action_group.get_action ("filter-location").set_sensitive (True)
  442.         printer_manager_action_group.get_action ("filter-manufacturer").set_sensitive (True)
  443.  
  444.         self.ui_manager = gtk.UIManager ()
  445.         self.ui_manager.insert_action_group (printer_manager_action_group, -1)
  446.         self.ui_manager.add_ui_from_string (
  447. """
  448. <ui>
  449.  <accelerator action="rename-printer"/>
  450.  <accelerator action="copy-printer"/>
  451.  <accelerator action="delete-printer"/>
  452.  <accelerator action="set-default-printer"/>
  453.  <accelerator action="edit-printer"/>
  454.  <accelerator action="create-class"/>
  455.  <accelerator action="view-print-queue"/>
  456.  <accelerator action="add-to-group"/>
  457.  <accelerator action="save-as-group"/>
  458.  <accelerator action="save-as-search-group"/>
  459.  <accelerator action="enable-printer"/>
  460.  <accelerator action="share-printer"/>
  461.  <accelerator action="filter-name"/>
  462.  <accelerator action="filter-description"/>
  463.  <accelerator action="filter-location"/>
  464.  <accelerator action="filter-manufacturer"/>
  465. </ui>
  466. """
  467. )
  468.         self.ui_manager.ensure_update ()
  469.         self.PrintersWindow.add_accel_group (self.ui_manager.get_accel_group ())
  470.  
  471.         self.printer_context_menu = gtk.Menu ()
  472.         for action_name in ["edit-printer",
  473.                             "copy-printer",
  474.                             "rename-printer",
  475.                             "delete-printer",
  476.                             None,
  477.                             "enable-printer",
  478.                             "share-printer",
  479.                             "create-class",
  480.                             "set-default-printer",
  481.                             None,
  482.                             "add-to-group",
  483.                             "view-print-queue"]:
  484.             if not action_name:
  485.                 item = gtk.SeparatorMenuItem ()
  486.             else:
  487.                 action = printer_manager_action_group.get_action (action_name)
  488.                 item = action.create_menu_item ()
  489.             item.show ()
  490.             self.printer_context_menu.append (item)
  491.         self.printer_menubar_item.set_submenu (self.printer_context_menu)
  492.  
  493.         self.jobviewers = [] # to keep track of jobviewer windows
  494.  
  495.         # Printer properties combo boxes
  496.         for combobox in [self.cmbPStartBanner,
  497.                          self.cmbPEndBanner,
  498.                          self.cmbPErrorPolicy,
  499.                          self.cmbPOperationPolicy]:
  500.             cell = gtk.CellRendererText ()
  501.             combobox.clear ()
  502.             combobox.pack_start (cell, True)
  503.             combobox.add_attribute (cell, 'text', 0)
  504.  
  505.         btn = self.btnRefreshMarkerLevels
  506.         btn.connect ("clicked", self.on_btnRefreshMarkerLevels_clicked)
  507.  
  508.         # Printer state reasons list
  509.         column = gtk.TreeViewColumn (_("Message"))
  510.         icon = gtk.CellRendererPixbuf ()
  511.         column.pack_start (icon, False)
  512.         text = gtk.CellRendererText ()
  513.         column.pack_start (text, False)
  514.         column.set_cell_data_func (icon, self.set_printer_state_reason_icon)
  515.         column.set_cell_data_func (text, self.set_printer_state_reason_text)
  516.         column.set_resizable (True)
  517.         self.tvPrinterStateReasons.append_column (column)
  518.         selection = self.tvPrinterStateReasons.get_selection ()
  519.         selection.set_mode (gtk.SELECTION_NONE)
  520.         store = gtk.ListStore (int, str)
  521.         self.tvPrinterStateReasons.set_model (store)
  522.  
  523.         # New Printer Dialog
  524.         self.newPrinterGUI = np = NewPrinterGUI(self)
  525.         np.NewPrinterWindow.set_transient_for(self.PrintersWindow)
  526.  
  527.         # Set up "About" dialog
  528.         self.AboutDialog.set_program_name(domain)
  529.         self.AboutDialog.set_version(config.VERSION)
  530.         self.AboutDialog.set_icon_name('printer')
  531.  
  532.         # Set up "Problems?" link button
  533.         class UnobtrusiveButton(gtk.Button):
  534.             def __init__ (self, **args):
  535.                 gtk.Button.__init__ (self, **args)
  536.                 self.set_relief (gtk.RELIEF_NONE)
  537.                 label = self.get_child ()
  538.                 text = label.get_text ()
  539.                 label.set_use_markup (True)
  540.                 label.set_markup ('<span size="small" ' +
  541.                                   'underline="single" ' +
  542.                                   'color="#0000ee">%s</span>' % text)
  543.  
  544.         problems = UnobtrusiveButton (label=_("Problems?"))
  545.         self.hboxServerBrowse.pack_end (problems, False, False, 0)
  546.         problems.connect ('clicked', self.on_problems_button_clicked)
  547.         problems.show ()
  548.  
  549.         self.static_tabs = 3
  550.  
  551.         gtk_label_autowrap.set_autowrap(self.PrintersWindow)
  552.  
  553.         try:
  554.             self.cups = authconn.Connection(self.PrintersWindow)
  555.         except RuntimeError:
  556.             self.cups = None
  557.  
  558.         self.status_context_id = self.statusbarMain.get_context_id(
  559.             "Connection")
  560.         self.setConnected()
  561.  
  562.         # Setup search and printer groups
  563.         self.setup_toolbar_for_search_entry ()
  564.         self.current_filter_text = ""
  565.         self.current_filter_mode = "filter-name"
  566.  
  567.         self.groups_pane = GroupsPane ()
  568.         self.current_groups_pane_item = self.groups_pane.get_selected_item ()
  569.         self.groups_pane.connect ('item-activated',
  570.                                   self.on_groups_pane_item_activated)
  571.         self.groups_pane.connect ('items-changed',
  572.                                   self.on_groups_pane_items_changed)
  573.         self.PrintersWindow.add_accel_group (
  574.             self.groups_pane.ui_manager.get_accel_group ())
  575.         self.view_area_hpaned = gtk.HPaned ()
  576.         self.view_area_hpaned.add1 (self.groups_pane)
  577.         self.groups_pane_visible = False
  578.         if self.groups_pane.n_groups () > 0:
  579.             self.view_groups.set_active (True)
  580.  
  581.         # Group menubar item
  582.         self.group_menubar_item.set_submenu (self.groups_pane.groups_menu)
  583.  
  584.         # "Add to Group" submenu
  585.         self.add_to_group_menu = gtk.Menu ()
  586.         self.update_add_to_group_menu ()
  587.         action = printer_manager_action_group.get_action ("add-to-group")
  588.         for proxy in action.get_proxies ():
  589.             if isinstance (proxy, gtk.MenuItem):
  590.                 item = proxy
  591.                 break
  592.         item.set_submenu (self.add_to_group_menu)
  593.  
  594.         # Search entry drop down menu
  595.         menu = gtk.Menu ()
  596.         for action_name in ["filter-name",
  597.                             "filter-description",
  598.                             "filter-location",
  599.                             "filter-manufacturer",
  600.                             None,
  601.                             "save-as-group",
  602.                             "save-as-search-group"]:
  603.             if not action_name:
  604.                 item = gtk.SeparatorMenuItem ()
  605.             else:
  606.                 action = printer_manager_action_group.get_action (action_name)
  607.                 item = action.create_menu_item ()
  608.             menu.append (item)
  609.         menu.show_all ()
  610.         self.search_entry.set_drop_down_menu (menu)
  611.  
  612.         # Setup icon view
  613.         self.mainlist = gtk.ListStore(gobject.TYPE_PYOBJECT, # Object
  614.                                       gtk.gdk.Pixbuf,        # Pixbuf
  615.                                       gobject.TYPE_STRING,   # Name
  616.                                       gobject.TYPE_STRING)   # Tooltip
  617.  
  618.         self.dests_iconview.set_model(self.mainlist)
  619.         self.dests_iconview.set_column_spacing (30)
  620.         self.dests_iconview.set_row_spacing (20)
  621.         self.dests_iconview.set_pixbuf_column (1)
  622.         self.dests_iconview.set_text_column (2)
  623.         self.dests_iconview.set_tooltip_column (3)
  624.         self.dests_iconview.set_has_tooltip(True)
  625.         self.dests_iconview.connect ('key-press-event',
  626.                                      self.dests_iconview_key_press_event)
  627.         self.dests_iconview.connect ('item-activated',
  628.                                      self.dests_iconview_item_activated)
  629.         self.dests_iconview.connect ('selection-changed',
  630.                                      self.dests_iconview_selection_changed)
  631.         self.dests_iconview.connect ('button-press-event',
  632.                                      self.dests_iconview_button_press_event)
  633.         self.dests_iconview.connect ('popup-menu',
  634.                                      self.dests_iconview_popup_menu)
  635.         self.dests_iconview_selection_changed (self.dests_iconview)
  636.         self.dests_iconview.enable_model_drag_source (gtk.gdk.BUTTON1_MASK,
  637.                                                       # should use a variable
  638.                                                       # instead of 0
  639.                                                       [("queue", 0, 0)],
  640.                                                       gtk.gdk.ACTION_COPY)
  641.         self.dests_iconview.connect ("drag-data-get",
  642.                                      self.dests_iconview_drag_data_get)
  643.  
  644.         # setup some lists
  645.         m = gtk.SELECTION_MULTIPLE
  646.         s = gtk.SELECTION_SINGLE
  647.         for name, treeview, selection_mode in (
  648.             (_("Members of this class"), self.tvClassMembers, m),
  649.             (_("Others"), self.tvClassNotMembers, m),
  650.             (_("Members of this class"), np.tvNCMembers, m),
  651.             (_("Others"), np.tvNCNotMembers, m),
  652.             (_("Devices"), np.tvNPDevices, s),
  653.             (_("Connections"), np.tvNPDeviceURIs, s),
  654.             (_("Makes"), np.tvNPMakes,s),
  655.             (_("Models"), np.tvNPModels,s),
  656.             (_("Drivers"), np.tvNPDrivers,s),
  657.             (_("Downloadable Drivers"), np.tvNPDownloadableDrivers,s),
  658.             (_("Users"), self.tvPUsers, m),
  659.             ):
  660.  
  661.             model = gtk.ListStore(str)
  662.             cell = gtk.CellRendererText()
  663.             column = gtk.TreeViewColumn(name, cell, text=0)
  664.             treeview.set_model(model)
  665.             treeview.append_column(column)
  666.             treeview.get_selection().set_mode(selection_mode)
  667.  
  668.         # Server Settings dialog
  669.         self.ServerSettingsDialog.connect ('response',
  670.                                            self.server_settings_response)
  671.  
  672.         # Printer Properties dialog
  673.         self.PrinterPropertiesDialog.connect ('response',
  674.                                               self.printer_properties_response)
  675.  
  676.         # Printer Properties tree view
  677.         col = gtk.TreeViewColumn ('', gtk.CellRendererText (), markup=0)
  678.         self.tvPrinterProperties.append_column (col)
  679.         sel = self.tvPrinterProperties.get_selection ()
  680.         sel.connect ('changed', self.on_tvPrinterProperties_selection_changed)
  681.         sel.set_mode (gtk.SELECTION_SINGLE)
  682.  
  683.         # Job Options widgets.
  684.         opts = [ options.OptionAlwaysShown ("copies", int, 1,
  685.                                             self.sbJOCopies,
  686.                                             self.btnJOResetCopies),
  687.  
  688.                  options.OptionAlwaysShownSpecial \
  689.                  ("orientation-requested", int, 3,
  690.                   self.cmbJOOrientationRequested,
  691.                   self.btnJOResetOrientationRequested,
  692.                   combobox_map = [3, 4, 5, 6],
  693.                   special_choice=_("Automatic rotation")),
  694.  
  695.                  options.OptionAlwaysShown ("fitplot", bool, False,
  696.                                             self.cbJOFitplot,
  697.                                             self.btnJOResetFitplot),
  698.  
  699.                  options.OptionAlwaysShown ("number-up", int, 1,
  700.                                             self.cmbJONumberUp,
  701.                                             self.btnJOResetNumberUp,
  702.                                             combobox_map=[1, 2, 4, 6, 9, 16]),
  703.  
  704.                  options.OptionAlwaysShown ("number-up-layout", str, "lrtb",
  705.                                             self.cmbJONumberUpLayout,
  706.                                             self.btnJOResetNumberUpLayout,
  707.                                             combobox_map = [ "lrtb",
  708.                                                              "lrbt",
  709.                                                              "rltb",
  710.                                                              "rlbt",
  711.                                                              "tblr",
  712.                                                              "tbrl",
  713.                                                              "btlr",
  714.                                                              "btrl" ]),
  715.  
  716.                  options.OptionAlwaysShown ("brightness", int, 100,
  717.                                             self.sbJOBrightness,
  718.                                             self.btnJOResetBrightness),
  719.  
  720.                  options.OptionAlwaysShown ("finishings", int, 3,
  721.                                             self.cmbJOFinishings,
  722.                                             self.btnJOResetFinishings,
  723.                                             combobox_map = [ 3, 4, 5, 6,
  724.                                                              7, 8, 9, 10,
  725.                                                              11, 12, 13, 14,
  726.                                                              20, 21, 22, 23,
  727.                                                              24, 25, 26, 27,
  728.                                                              28, 29, 30, 31,
  729.                                                              50, 51, 52, 53 ],
  730.                                             use_supported = True),
  731.  
  732.                  options.OptionAlwaysShown ("job-priority", int, 50,
  733.                                             self.sbJOJobPriority,
  734.                                             self.btnJOResetJobPriority),
  735.  
  736.                  options.OptionAlwaysShown ("media", str,
  737.                                             "A4", # This is the default for
  738.                                                   # when media-default is
  739.                                                   # not supplied by the IPP
  740.                                                   # server.  Fortunately it
  741.                                                   # is a mandatory attribute.
  742.                                             self.cmbJOMedia,
  743.                                             self.btnJOResetMedia,
  744.                                             use_supported = True),
  745.  
  746.                  options.OptionAlwaysShown ("sides", str, "one-sided",
  747.                                             self.cmbJOSides,
  748.                                             self.btnJOResetSides,
  749.                                             combobox_map =
  750.                                             [ "one-sided",
  751.                                               "two-sided-long-edge",
  752.                                               "two-sided-short-edge" ]),
  753.  
  754.                  options.OptionAlwaysShown ("job-hold-until", str,
  755.                                             "no-hold",
  756.                                             self.cmbJOHoldUntil,
  757.                                             self.btnJOResetHoldUntil,
  758.                                             use_supported = True),
  759.  
  760.                  options.OptionAlwaysShown ("mirror", bool, False,
  761.                                             self.cbJOMirror,
  762.                                             self.btnJOResetMirror),
  763.  
  764.                  options.OptionAlwaysShown ("scaling", int, 100,
  765.                                             self.sbJOScaling,
  766.                                             self.btnJOResetScaling),
  767.  
  768.                  options.OptionAlwaysShown ("saturation", int, 100,
  769.                                             self.sbJOSaturation,
  770.                                             self.btnJOResetSaturation),
  771.  
  772.                  options.OptionAlwaysShown ("hue", int, 0,
  773.                                             self.sbJOHue,
  774.                                             self.btnJOResetHue),
  775.  
  776.                  options.OptionAlwaysShown ("gamma", int, 1000,
  777.                                             self.sbJOGamma,
  778.                                             self.btnJOResetGamma),
  779.  
  780.                  options.OptionAlwaysShown ("cpi", float, 10.0,
  781.                                             self.sbJOCpi, self.btnJOResetCpi),
  782.  
  783.                  options.OptionAlwaysShown ("lpi", float, 6.0,
  784.                                             self.sbJOLpi, self.btnJOResetLpi),
  785.  
  786.                  options.OptionAlwaysShown ("page-left", int, 0,
  787.                                             self.sbJOPageLeft,
  788.                                             self.btnJOResetPageLeft),
  789.  
  790.                  options.OptionAlwaysShown ("page-right", int, 0,
  791.                                             self.sbJOPageRight,
  792.                                             self.btnJOResetPageRight),
  793.  
  794.                  options.OptionAlwaysShown ("page-top", int, 0,
  795.                                             self.sbJOPageTop,
  796.                                             self.btnJOResetPageTop),
  797.  
  798.                  options.OptionAlwaysShown ("page-bottom", int, 0,
  799.                                             self.sbJOPageBottom,
  800.                                             self.btnJOResetPageBottom),
  801.  
  802.                  options.OptionAlwaysShown ("prettyprint", bool, False,
  803.                                             self.cbJOPrettyPrint,
  804.                                             self.btnJOResetPrettyPrint),
  805.  
  806.                  options.OptionAlwaysShown ("wrap", bool, False, self.cbJOWrap,
  807.                                             self.btnJOResetWrap),
  808.  
  809.                  options.OptionAlwaysShown ("columns", int, 1,
  810.                                             self.sbJOColumns,
  811.                                             self.btnJOResetColumns),
  812.                  ]
  813.         self.job_options_widgets = {}
  814.         self.job_options_buttons = {}
  815.         for option in opts:
  816.             self.job_options_widgets[option.widget] = option
  817.             self.job_options_buttons[option.button] = option
  818.  
  819.         self.monitor = monitor.Monitor (self, monitor_jobs=False)
  820.  
  821.         try:
  822.             self.populateList()
  823.         except cups.HTTPError, (s,):
  824.             self.cups = None
  825.             self.setConnected()
  826.             self.populateList()
  827.             show_HTTP_Error(s, self.PrintersWindow)
  828.  
  829.         if len (self.printers) > 3:
  830.             self.PrintersWindow.set_default_size (550, 400)
  831.  
  832.         self.PrintersWindow.show()
  833.  
  834.         if setup_printer:
  835.             self.device_uri = setup_printer
  836.             self.devid = devid
  837.             self.ppd = None
  838.             try:
  839.                 self.on_autodetected_printer_without_driver(None)
  840.             except RuntimeError:
  841.                 pass
  842.  
  843.         if configure_printer:
  844.             # Need to find the entry in the iconview model and activate it.
  845.             try:
  846.                 self.display_properties_dialog_for (configure_printer)
  847.                 if print_test_page:
  848.                     self.btnPrintTestPage.clicked ()
  849.                 if change_ppd:
  850.                     self.btnChangePPD.clicked ()
  851.             except RuntimeError:
  852.                 pass
  853.  
  854.     def display_properties_dialog_for (self, queue):
  855.         model = self.dests_iconview.get_model ()
  856.         iter = model.get_iter_first ()
  857.         while iter != None:
  858.             name = unicode (model.get_value (iter, 2))
  859.             if name == queue:
  860.                 path = model.get_path (iter)
  861.                 self.dests_iconview.scroll_to_path (path, True, 0.5, 0.5)
  862.                 self.dests_iconview.set_cursor (path)
  863.                 self.dests_iconview.item_activated (path)
  864.                 break
  865.             iter = model.iter_next (iter)
  866.  
  867.         if iter == None:
  868.             raise RuntimeError
  869.  
  870.     def setup_toolbar_for_search_entry (self):
  871.         separator = gtk.SeparatorToolItem ()
  872.         separator.set_draw (False)
  873.  
  874.         self.toolbar.insert (separator, -1)
  875.         self.toolbar.child_set_property (separator, "expand", True)
  876.  
  877.         self.search_entry = ToolbarSearchEntry ()
  878.         self.search_entry.connect ('search', self.on_search_entry_search)
  879.  
  880.         tool_item = gtk.ToolItem ()
  881.         tool_item.add (self.search_entry)
  882.         self.toolbar.insert (tool_item, -1)
  883.         self.toolbar.show_all ()
  884.  
  885.     def on_search_entry_search (self, UNUSED, text):
  886.         self.ui_manager.get_action ("/save-as-group").set_sensitive (
  887.             text and True or False)
  888.         self.ui_manager.get_action ("/save-as-search-group").set_sensitive (
  889.             text and True or False)
  890.         self.current_filter_text = text
  891.         self.populateList ()
  892.  
  893.     def on_groups_pane_item_activated (self, UNUSED, item):
  894.         self.search_entry.clear ()
  895.  
  896.         if isinstance (item, SavedSearchGroupItem):
  897.             crit = item.criteria[0]
  898.             if crit.subject == SearchCriterion.SUBJECT_NAME:
  899.                 self.ui_manager.get_action ("/filter-name").activate ()
  900.             elif crit.subject == SearchCriterion.SUBJECT_DESC:
  901.                 self.ui_manager.get_action ("/filter-description").activate ()
  902.             elif crit.subject == SearchCriterion.SUBJECT_LOCATION:
  903.                 self.ui_manager.get_action ("/filter-location").activate ()
  904.             elif crit.subject == SearchCriterion.SUBJECT_MANUF:
  905.                 self.ui_manager.get_action ("/filter-manufacturer").activate ()
  906.             else:
  907.                 nonfatalException ()
  908.  
  909.             self.search_entry.set_text (crit.value)
  910.  
  911.         self.current_groups_pane_item = item
  912.         self.populateList ()
  913.  
  914.     def on_add_to_group_menu_item_activate (self, menuitem, group):
  915.         group.add_queues (self.groups_pane.currently_selected_queues)
  916.  
  917.     def update_add_to_group_menu (self):
  918.         for child in self.add_to_group_menu.get_children ():
  919.             self.add_to_group_menu.remove (child)
  920.         static_groups = self.groups_pane.get_static_groups ()
  921.         for group in static_groups:
  922.             item = gtk.MenuItem (group.name, False)
  923.             item.connect ("activate",
  924.                           self.on_add_to_group_menu_item_activate, group)
  925.             self.add_to_group_menu.append (item)
  926.         if len (static_groups) > 0:
  927.             item = gtk.SeparatorMenuItem ()
  928.             self.add_to_group_menu.append (item)
  929.         action = self.groups_pane.ui_manager.get_action ("/new-group-from-selection")
  930.         item = action.create_menu_item ()
  931.         self.add_to_group_menu.append (item)
  932.         self.add_to_group_menu.show_all ()
  933.  
  934.     def on_groups_pane_items_changed (self, UNUSED):
  935.         if not self.groups_pane_visible:
  936.             self.view_groups.set_active (True)
  937.         self.update_add_to_group_menu ()
  938.  
  939.     def on_filter_criterion_changed (self, UNUSED, selected_action):
  940.         self.current_filter_mode = selected_action.get_name ()
  941.         self.populateList ()
  942.  
  943.     def dests_iconview_item_activated (self, iconview, path):
  944.         model = iconview.get_model ()
  945.         iter = model.get_iter (path)
  946.         name = unicode (model.get_value (iter, 2))
  947.         object = model.get_value (iter, 0)
  948.  
  949.         try:
  950.             self.fillPrinterTab (name)
  951.         except cups.IPPError, (e, m):
  952.             show_IPP_Error (e, m, self.PrintersWindow)
  953.             if e == cups.IPP_SERVICE_UNAVAILABLE:
  954.                 self.cups = None
  955.                 self.setConnected ()
  956.                 self.populateList ()
  957.             return
  958.         except RuntimeError:
  959.             # Perhaps cupsGetPPD2 failed for a browsed printer.
  960.             return
  961.  
  962.         self.PrinterPropertiesDialog.set_transient_for (self.PrintersWindow)
  963.         for button in [self.btnPrinterPropertiesCancel,
  964.                        self.btnPrinterPropertiesOK,
  965.                        self.btnPrinterPropertiesApply]:
  966.             if object.discovered:
  967.                 button.hide ()
  968.             else:
  969.                 button.show ()
  970.         if object.discovered:
  971.             self.btnPrinterPropertiesClose.show ()
  972.         else:
  973.             self.btnPrinterPropertiesClose.hide ()
  974.         self.setDataButtonState ()
  975.         treeview = self.tvPrinterProperties
  976.         treeview.set_cursor ((0,))
  977.         host = CUPS_server_hostname ()
  978.         self.PrinterPropertiesDialog.set_title (_("Printer Properties - "
  979.                                                   "'%s' on %s") % (name, host))
  980.         self.PrinterPropertiesDialog.set_focus_on_map (self.focus_on_map)
  981.         self.PrinterPropertiesDialog.show ()
  982.  
  983.     def printer_properties_response (self, dialog, response):
  984.         if response == gtk.RESPONSE_REJECT:
  985.             # The Conflict button was pressed.
  986.             message = _("There are conflicting options.\n"
  987.                         "Changes can only be applied after\n"
  988.                         "these conflicts are resolved.")
  989.             message += "\n\n"
  990.             for option in self.conflicts:
  991.                 message += option.option.text + "\n"
  992.  
  993.             dialog = gtk.MessageDialog(self.PrinterPropertiesDialog,
  994.                                        gtk.DIALOG_DESTROY_WITH_PARENT |
  995.                                        gtk.DIALOG_MODAL,
  996.                                        gtk.MESSAGE_WARNING,
  997.                                        gtk.BUTTONS_CLOSE,
  998.                                        message)
  999.             dialog.run()
  1000.             dialog.destroy()
  1001.             return
  1002.  
  1003.         if (response == gtk.RESPONSE_OK or
  1004.             response == gtk.RESPONSE_APPLY):
  1005.             success = self.save_printer (self.printer)
  1006.  
  1007.         if response == gtk.RESPONSE_APPLY:
  1008.             try:
  1009.                 self.fillPrinterTab (self.printer.name)
  1010.             except:
  1011.                 pass
  1012.  
  1013.             self.setDataButtonState ()
  1014.  
  1015.         if ((response == gtk.RESPONSE_OK and not success) or
  1016.             response == gtk.RESPONSE_CANCEL):
  1017.             self.printer = None
  1018.             dialog.hide ()
  1019.  
  1020.     def dests_iconview_selection_changed (self, iconview):
  1021.         self.updating_widgets = True
  1022.         paths = iconview.get_selected_items ()
  1023.         any_disabled = False
  1024.         any_enabled = False
  1025.         any_discovered = False
  1026.         any_shared = False
  1027.         any_unshared = False
  1028.         self.groups_pane.currently_selected_queues = []
  1029.         model = iconview.get_model ()
  1030.         for path in paths:
  1031.             iter = model.get_iter (path)
  1032.             object = model.get_value (iter, 0)
  1033.             name = unicode (model.get_value (iter, 2))
  1034.             self.groups_pane.currently_selected_queues.append (name)
  1035.             if object.discovered:
  1036.                 any_discovered = True
  1037.             if object.enabled:
  1038.                 any_enabled = True
  1039.             else:
  1040.                 any_disabled = True
  1041.             if object.is_shared:
  1042.                 any_shared = True
  1043.             else:
  1044.                 any_unshared = True
  1045.  
  1046.         n = len (paths)
  1047.         self.groups_pane.ui_manager.get_action (
  1048.             "/new-group-from-selection").set_sensitive (n > 0)
  1049.  
  1050.         self.ui_manager.get_action ("/edit-printer").set_sensitive (n == 1)
  1051.  
  1052.         self.ui_manager.get_action ("/copy-printer").set_sensitive (n == 1)
  1053.  
  1054.         self.ui_manager.get_action ("/rename-printer").set_sensitive (
  1055.             n == 1 and not any_discovered)
  1056.  
  1057.         userdef = userdefault.UserDefaultPrinter ().get ()
  1058.         if (n != 1 or
  1059.             (userdef == None and self.default_printer == name)):
  1060.             set_default_sensitivity = False
  1061.         else:
  1062.             set_default_sensitivity = True
  1063.  
  1064.         self.ui_manager.get_action ("/set-default-printer").set_sensitive (
  1065.             set_default_sensitivity)
  1066.  
  1067.         action = self.ui_manager.get_action ("/enable-printer")
  1068.         action.set_sensitive (n > 0 and not any_discovered)
  1069.         for widget in action.get_proxies ():
  1070.             if isinstance (widget, gtk.CheckMenuItem):
  1071.                 widget.set_inconsistent (n > 1 and any_enabled and any_disabled)
  1072.         action.set_active (any_discovered or not any_disabled)
  1073.  
  1074.         action = self.ui_manager.get_action ("/share-printer")
  1075.         action.set_sensitive (n > 0 and not any_discovered)
  1076.         for widget in action.get_proxies ():
  1077.             if isinstance (widget, gtk.CheckMenuItem):
  1078.                 widget.set_inconsistent (n > 1 and any_shared and any_unshared)
  1079.         action.set_active (any_discovered or not any_unshared)
  1080.  
  1081.         self.ui_manager.get_action ("/delete-printer").set_sensitive (
  1082.             n > 0 and not any_discovered)
  1083.  
  1084.         self.ui_manager.get_action ("/create-class").set_sensitive (n > 1)
  1085.  
  1086.         self.ui_manager.get_action ("/add-to-group").set_sensitive (n > 0)
  1087.  
  1088.         self.updating_widgets = False
  1089.  
  1090.     def dests_iconview_popup_menu (self, iconview):
  1091.         self.printer_context_menu.popup (None, None, None, 0, 0L)
  1092.  
  1093.     def dests_iconview_button_press_event (self, iconview, event):
  1094.         if event.button > 1:
  1095.             click_path = iconview.get_path_at_pos (int (event.x),
  1096.                                                    int (event.y))
  1097.             paths = iconview.get_selected_items ()
  1098.             if click_path == None:
  1099.                 iconview.unselect_all ()
  1100.             elif click_path not in paths:
  1101.                 iconview.unselect_all ()
  1102.                 iconview.select_path (click_path)
  1103.                 cells = iconview.get_cells ()
  1104.                 for cell in cells:
  1105.                     if type (cell) == gtk.CellRendererText:
  1106.                         break
  1107.                 iconview.set_cursor (click_path, cell)
  1108.             self.printer_context_menu.popup (None, None, None,
  1109.                                              event.button, event.time)
  1110.         return False
  1111.  
  1112.     def dests_iconview_key_press_event (self, iconview, event):
  1113.         modifiers = gtk.accelerator_get_default_mod_mask ()
  1114.  
  1115.         if ((event.keyval == gtk.keysyms.BackSpace or
  1116.              event.keyval == gtk.keysyms.Delete or
  1117.              event.keyval == gtk.keysyms.KP_Delete) and
  1118.             ((event.state & modifiers) == 0)):
  1119.  
  1120.             self.ui_manager.get_action ("/delete-printer").activate ()
  1121.             return True
  1122.  
  1123.         if ((event.keyval == gtk.keysyms.F2) and
  1124.             ((event.state & modifiers) == 0)):
  1125.  
  1126.             self.ui_manager.get_action ("/rename-printer").activate ()
  1127.             return True
  1128.  
  1129.         return False
  1130.  
  1131.     def dests_iconview_drag_data_get (self, iconview, context,
  1132.                                       selection_data, info, timestamp):
  1133.         if info == 0: # FIXME: should use an "enum" here
  1134.             model = iconview.get_model ()
  1135.             paths = iconview.get_selected_items ()
  1136.             selected_printer_names = ""
  1137.             for path in paths:
  1138.                 selected_printer_names += \
  1139.                     model.get_value (model.get_iter (path), 2) + "\n"
  1140.  
  1141.             if len (selected_printer_names) > 0:
  1142.                 selection_data.set ("queue", 8, selected_printer_names)
  1143.         else:
  1144.             nonfatalException ()
  1145.  
  1146.     def on_server_settings_activate (self, menuitem):
  1147.         try:
  1148.             self.fillServerTab ()
  1149.         except cups.IPPError:
  1150.             # Not authorized.
  1151.             return
  1152.  
  1153.         self.ServerSettingsDialog.set_transient_for (self.PrintersWindow)
  1154.         self.ServerSettingsDialog.show ()
  1155.  
  1156.     def server_settings_response (self, dialog, response):
  1157.         if response == gtk.RESPONSE_OK:
  1158.             # OK
  1159.             if not self.save_serversettings ():
  1160.                 dialog.hide ()
  1161.         elif response == gtk.RESPONSE_YES:
  1162.             # Advanced
  1163.             try:
  1164.                 AdvancedServerSettingsDialog (self.cups, dialog,
  1165.                                               self.on_adv_server_settings_apply)
  1166.             except:
  1167.                 return
  1168.         else:
  1169.             dialog.hide ()
  1170.  
  1171.     def on_adv_server_settings_apply (self):
  1172.         try:
  1173.             self.fillServerTab ()
  1174.         except cups.IPPError:
  1175.             self.ServerSettingsDialog.hide ()
  1176.  
  1177.     def busy (self, win = None):
  1178.         try:
  1179.             if not win:
  1180.                 win = self.PrintersWindow
  1181.             gdkwin = win.window
  1182.             if gdkwin:
  1183.                 gdkwin.set_cursor (busy_cursor)
  1184.                 while gtk.events_pending ():
  1185.                     gtk.main_iteration ()
  1186.         except:
  1187.             nonfatalException ()
  1188.  
  1189.     def ready (self, win = None):
  1190.         try:
  1191.             if not win:
  1192.                 win = self.PrintersWindow
  1193.             gdkwin = win.window
  1194.             if gdkwin:
  1195.                 gdkwin.set_cursor (None)
  1196.                 while gtk.events_pending ():
  1197.                     gtk.main_iteration ()
  1198.         except:
  1199.             nonfatalException ()
  1200.  
  1201.     def setConnected(self):
  1202.         connected = bool(self.cups)
  1203.  
  1204.         host = CUPS_server_hostname ()
  1205.         self.PrintersWindow.set_title(_("Printer configuration - %s") % host)
  1206.         self.PrintersWindow.set_focus_on_map (self.focus_on_map)
  1207.  
  1208.         if connected:
  1209.             status_msg = _("Connected to %s") % host
  1210.         else:
  1211.             status_msg = _("Not connected")
  1212.         self.statusbarMain.push(self.status_context_id, status_msg)
  1213.  
  1214.         for widget in (self.btnNew,
  1215.                        self.new_printer, self.new_class,
  1216.                        self.chkServerBrowse, self.chkServerShare,
  1217.                        self.chkServerRemoteAdmin,
  1218.                        self.chkServerAllowCancelAll,
  1219.                        self.chkServerLogDebug,
  1220.                        self.server_settings_menu_entry):
  1221.             widget.set_sensitive(connected)
  1222.  
  1223.         sharing = self.chkServerShare.get_active ()
  1224.         self.chkServerShareAny.set_sensitive (sharing)
  1225.  
  1226.         try:
  1227.             del self.server_settings
  1228.         except:
  1229.             pass
  1230.  
  1231.     def getServers(self):
  1232.         self.servers.discard(None)
  1233.         known_servers = list(self.servers)
  1234.         known_servers.sort()
  1235.         return known_servers
  1236.  
  1237.     def populateList(self, prompt_allowed=True):
  1238.         # Save selection of printers.
  1239.         selected_printers = set()
  1240.         paths = self.dests_iconview.get_selected_items ()
  1241.         model = self.dests_iconview.get_model ()
  1242.         for path in paths:
  1243.             iter = model.get_iter (path)
  1244.             name = unicode (model.get_value (iter, 2))
  1245.             selected_printers.add (name)
  1246.  
  1247.         if self.cups:
  1248.             self.cups._set_prompt_allowed (prompt_allowed)
  1249.             self.cups._begin_operation (_("obtaining queue details"))
  1250.             try:
  1251.                 # get Printers
  1252.                 self.printers = cupshelpers.getPrinters(self.cups)
  1253.  
  1254.                 # Get default printer.
  1255.                 self.default_printer = self.cups.getDefault ()
  1256.             except cups.IPPError, (e, m):
  1257.                 show_IPP_Error(e, m, self.PrintersWindow)
  1258.                 self.printers = {}
  1259.                 self.default_printer = None
  1260.  
  1261.             self.cups._end_operation ()
  1262.             self.cups._set_prompt_allowed (True)
  1263.         else:
  1264.             self.printers = {}
  1265.             self.default_printer = None
  1266.  
  1267.         for name, printer in self.printers.iteritems():
  1268.             self.servers.add(printer.getServer())
  1269.  
  1270.         userdef = userdefault.UserDefaultPrinter ().get ()
  1271.  
  1272.         local_printers = []
  1273.         local_classes = []
  1274.         remote_printers = []
  1275.         remote_classes = []
  1276.  
  1277.         # Choose a view according to the groups pane item
  1278.         if (isinstance (self.current_groups_pane_item, AllPrintersItem) or
  1279.             isinstance (self.current_groups_pane_item, SavedSearchGroupItem)):
  1280.             delete_action = self.ui_manager.get_action ("/delete-printer")
  1281.             delete_action.set_properties (label = None)
  1282.             printers_set = self.printers
  1283.         elif isinstance (self.current_groups_pane_item, FavouritesItem):
  1284.             printers_set = {} # FIXME
  1285.         elif isinstance (self.current_groups_pane_item, StaticGroupItem):
  1286.             delete_action = self.ui_manager.get_action ("/delete-printer")
  1287.             delete_action.set_properties (label = _("Remove from Group"))
  1288.             printers_set = {}
  1289.             deleted_printers = []
  1290.             for printer_name in self.current_groups_pane_item.printer_queues:
  1291.                 try:
  1292.                     printer = self.printers[printer_name]
  1293.                     printers_set[printer_name] = printer
  1294.                 except KeyError:
  1295.                     deleted_printers.append (printer_name)
  1296.             self.current_groups_pane_item.remove_queues (deleted_printers)
  1297.         else:
  1298.             printers_set = self.printers
  1299.             nonfatalException ()
  1300.  
  1301.         # Filter printers
  1302.         if len (self.current_filter_text) > 0:
  1303.             printers_subset = {}
  1304.             pattern = re.compile (self.current_filter_text, re.I) # ignore case
  1305.  
  1306.             if self.current_filter_mode == "filter-name":
  1307.                 for name in printers_set.keys ():
  1308.                     if pattern.search (name) != None:
  1309.                         printers_subset[name] = printers_set[name]
  1310.             elif self.current_filter_mode == "filter-description":
  1311.                 for name, printer in printers_set.iteritems ():
  1312.                     if pattern.search (printer.info) != None:
  1313.                         printers_subset[name] = printers_set[name]
  1314.             elif self.current_filter_mode == "filter-location":
  1315.                 for name, printer in printers_set.iteritems ():
  1316.                     if pattern.search (printer.location) != None:
  1317.                         printers_subset[name] = printers_set[name]
  1318.             elif self.current_filter_mode == "filter-manufacturer":
  1319.                 for name, printer in printers_set.iteritems ():
  1320.                     if pattern.search (printer.make_and_model) != None:
  1321.                         printers_subset[name] = printers_set[name]
  1322.             else:
  1323.                 nonfatalException ()
  1324.  
  1325.             printers_set = printers_subset
  1326.  
  1327.         if not self.view_discovered_printers.get_active ():
  1328.             printers_subset = {}
  1329.             for name, printer in printers_set.iteritems ():
  1330.                 if not printer.discovered:
  1331.                     printers_subset[name] = printer
  1332.  
  1333.             printers_set = printers_subset
  1334.  
  1335.         for name, printer in printers_set.iteritems():
  1336.             if printer.remote:
  1337.                 if printer.is_class: remote_classes.append(name)
  1338.                 else: remote_printers.append(name)
  1339.             else:
  1340.                 if printer.is_class: local_classes.append(name)
  1341.                 else: local_printers.append(name)
  1342.  
  1343.         local_printers.sort()
  1344.         local_classes.sort()
  1345.         remote_printers.sort()
  1346.         remote_classes.sort()
  1347.  
  1348.         # remove old printers/classes
  1349.         self.mainlist.clear ()
  1350.  
  1351.         # add new
  1352.         PRINTER_TYPE = { 'discovered-printer':
  1353.                              (_("Network printer (discovered)"),
  1354.                               'i-network-printer'),
  1355.                          'discovered-class':
  1356.                              (_("Network class (discovered)"),
  1357.                               'i-network-printer'),
  1358.                          'local-printer':
  1359.                              (_("Printer"),
  1360.                               'gnome-dev-printer'),
  1361.                          'local-fax':
  1362.                              (_("Fax"),
  1363.                               'gnome-dev-printer'),
  1364.                          'local-class':
  1365.                              (_("Class"),
  1366.                               'gnome-dev-printer'),
  1367.                          'ipp-printer':
  1368.                              (_("Network printer"),
  1369.                               'i-network-printer'),
  1370.                          'smb-printer':
  1371.                              (_("Network print share"),
  1372.                               'gnome-dev-printer'),
  1373.                          'network-printer':
  1374.                              (_("Network printer"),
  1375.                               'i-network-printer'),
  1376.                          }
  1377.         theme = gtk.icon_theme_get_default ()
  1378.         for printers in (local_printers,
  1379.                          local_classes,
  1380.                          remote_printers,
  1381.                          remote_classes):
  1382.             if not printers: continue
  1383.             for name in printers:
  1384.                 type = 'local-printer'
  1385.                 object = printers_set[name]
  1386.                 if object.discovered:
  1387.                     if object.is_class:
  1388.                         type = 'discovered-class'
  1389.                     else:
  1390.                         type = 'discovered-printer'
  1391.                 elif object.is_class:
  1392.                     type = 'local-class'
  1393.                 else:
  1394.                     (scheme, rest) = urllib.splittype (object.device_uri)
  1395.                     if scheme == 'ipp':
  1396.                         type = 'ipp-printer'
  1397.                     elif scheme == 'smb':
  1398.                         type = 'smb-printer'
  1399.                     elif scheme == 'hpfax':
  1400.                         type = 'local-fax'
  1401.                     elif scheme in ['socket', 'lpd']:
  1402.                         type = 'network-printer'
  1403.  
  1404.                 (tip, icon) = PRINTER_TYPE[type]
  1405.                 (w, h) = gtk.icon_size_lookup (gtk.ICON_SIZE_DIALOG)
  1406.                 try:
  1407.                     pixbuf = theme.load_icon (icon, w, 0)
  1408.                 except gobject.GError:
  1409.                     # Not in theme.
  1410.                     pixbuf = None
  1411.                     for p in [iconpath, 'icons/']:
  1412.                         try:
  1413.                             pixbuf = gtk.gdk.pixbuf_new_from_file ("%s%s.png" %
  1414.                                                                    (p, icon))
  1415.                             break
  1416.                         except gobject.GError:
  1417.                             pass
  1418.  
  1419.                     if pixbuf == None:
  1420.                         try:
  1421.                             pixbuf = theme.load_icon ('printer', w, 0)
  1422.                         except:
  1423.                             # Just create an empty pixbuf.
  1424.                             pixbuf = gtk.gdk.Pixbuf (gtk.gdk.COLORSPACE_RGB,
  1425.                                                      True, 8, w, h)
  1426.                             pixbuf.fill (0)
  1427.  
  1428.                 def_emblem = None
  1429.                 emblem = None
  1430.                 if name == self.default_printer:
  1431.                     def_emblem = 'emblem-default'
  1432.                 elif name == userdef:
  1433.                     def_emblem = 'emblem-favorite'
  1434.  
  1435.                 if not emblem:
  1436.                     attrs = object.other_attributes
  1437.                     reasons = attrs.get ('printer-state-reasons', [])
  1438.                     worst_reason = None
  1439.                     for reason in reasons:
  1440.                         if reason == "none":
  1441.                             break
  1442.  
  1443.                         if reason == "paused":
  1444.                             emblem = gtk.STOCK_MEDIA_PAUSE
  1445.                             continue
  1446.  
  1447.                         r = statereason.StateReason (object.name, reason)
  1448.                         if worst_reason == None:
  1449.                             worst_reason = r
  1450.                         elif r > worst_reason:
  1451.                             worst_reason = r
  1452.  
  1453.                     if worst_reason:
  1454.                         level = worst_reason.get_level ()
  1455.                         emblem = worst_reason.LEVEL_ICON[level]
  1456.  
  1457.                 if not emblem and not object.enabled:
  1458.                     emblem = gtk.STOCK_MEDIA_PAUSE
  1459.  
  1460.                 if object.rejecting:
  1461.                     # Show the icon as insensitive
  1462.                     copy = pixbuf.copy ()
  1463.                     copy.fill (0)
  1464.                     pixbuf.composite (copy, 0, 0,
  1465.                                       copy.get_width(), copy.get_height(),
  1466.                                       0, 0, 1.0, 1.0,
  1467.                                       gtk.gdk.INTERP_BILINEAR, 127)
  1468.                     pixbuf = copy
  1469.  
  1470.                 if def_emblem:
  1471.                     (w, h) = gtk.icon_size_lookup (gtk.ICON_SIZE_DIALOG)
  1472.                     default_emblem = theme.load_icon (def_emblem, w/2, 0)
  1473.                     copy = pixbuf.copy ()
  1474.                     default_emblem.composite (copy, 0, 0,
  1475.                                               copy.get_width (),
  1476.                                               copy.get_height (),
  1477.                                               0, 0,
  1478.                                               1.0, 1.0,
  1479.                                               gtk.gdk.INTERP_NEAREST, 255)
  1480.                     pixbuf = copy
  1481.  
  1482.                 if emblem:
  1483.                     (w, h) = gtk.icon_size_lookup (gtk.ICON_SIZE_DIALOG)
  1484.                     other_emblem = theme.load_icon (emblem, w/2, 0)
  1485.                     copy = pixbuf.copy ()
  1486.                     other_emblem.composite (copy, 0, 0,
  1487.                                             copy.get_width (),
  1488.                                             copy.get_height (),
  1489.                                             copy.get_width () / 2,
  1490.                                             copy.get_height () / 2,
  1491.                                             1.0, 1.0,
  1492.                                             gtk.gdk.INTERP_NEAREST, 255)
  1493.                     pixbuf = copy
  1494.  
  1495.                 self.mainlist.append (row=[object, pixbuf, name, tip])
  1496.  
  1497.         # Restore selection of printers.
  1498.         model = self.dests_iconview.get_model ()
  1499.         def maybe_select (model, path, iter):
  1500.             name = unicode (model.get_value (iter, 2))
  1501.             if name in selected_printers:
  1502.                 self.dests_iconview.select_path (path)
  1503.         model.foreach (maybe_select)
  1504.  
  1505.         if (self.printer != None and
  1506.             self.printer.name not in self.printers.keys ()):
  1507.             # The printer we're editing has been deleted.
  1508.             self.PrinterPropertiesDialog.response (gtk.RESPONSE_CANCEL)
  1509.  
  1510.     # Connect to Server
  1511.  
  1512.     def on_connect_servername_changed(self, widget):
  1513.         self.btnConnect.set_sensitive (len (widget.get_active_text ()) > 0)
  1514.  
  1515.     def on_connect_activate(self, widget):
  1516.         # Use browsed queues to build up a list of known IPP servers
  1517.         servers = self.getServers()
  1518.         current_server = (self.printer and self.printer.getServer()) \
  1519.                          or cups.getServer()
  1520.  
  1521.         store = gtk.ListStore (gobject.TYPE_STRING)
  1522.         self.cmbServername.set_model(store)
  1523.         for server in servers:
  1524.             self.cmbServername.append_text(server)
  1525.         self.cmbServername.show()
  1526.  
  1527.         self.cmbServername.child.set_text (current_server)
  1528.         self.chkEncrypted.set_active (cups.getEncryption() ==
  1529.                                       cups.HTTP_ENCRYPT_ALWAYS)
  1530.  
  1531.         self.cmbServername.child.set_activates_default (True)
  1532.         self.cmbServername.grab_focus ()
  1533.         self.ConnectDialog.set_transient_for (self.PrintersWindow)
  1534.         response = self.ConnectDialog.run()
  1535.  
  1536.         self.ConnectDialog.hide()
  1537.  
  1538.         if response != gtk.RESPONSE_OK:
  1539.             return
  1540.  
  1541.         if self.chkEncrypted.get_active():
  1542.             cups.setEncryption(cups.HTTP_ENCRYPT_ALWAYS)
  1543.         else:
  1544.             cups.setEncryption(cups.HTTP_ENCRYPT_IF_REQUESTED)
  1545.         self.connect_encrypt = cups.getEncryption ()
  1546.  
  1547.         servername = self.cmbServername.child.get_text()
  1548.  
  1549.         self.lblConnecting.set_markup(_("<i>Opening connection to %s</i>") %
  1550.                                       servername)
  1551.         self.newPrinterGUI.dropPPDs()
  1552.         self.ConnectingDialog.set_transient_for(self.PrintersWindow)
  1553.         self.ConnectingDialog.show()
  1554.         gobject.timeout_add (40, self.update_connecting_pbar)
  1555.         self.connect_server = servername
  1556.         # We need to set the connecting user in this thread as well.
  1557.         cups.setServer(self.connect_server)
  1558.         cups.setUser('')
  1559.         self.connect_user = cups.getUser()
  1560.         # Now start a new thread for connection.
  1561.         self.connect_thread = thread.start_new_thread(self.connect,
  1562.                                                       (self.PrintersWindow,))
  1563.  
  1564.     def update_connecting_pbar (self):
  1565.         if not self.ConnectingDialog.get_property ("visible"):
  1566.             return False # stop animation
  1567.  
  1568.         self.pbarConnecting.pulse ()
  1569.         return True
  1570.  
  1571.     def on_connectingdialog_delete (self, widget, event):
  1572.         self.on_cancel_connect_clicked (widget)
  1573.         return True
  1574.  
  1575.     def on_cancel_connect_clicked(self, widget):
  1576.         """
  1577.         Stop connection to new server
  1578.         (Doesn't really stop but sets flag for the connecting thread to
  1579.         ignore the connection)
  1580.         """
  1581.         self.connect_thread = None
  1582.         self.ConnectingDialog.hide()
  1583.  
  1584.     def connect(self, parent=None):
  1585.         """
  1586.         Open a connection to a new server. Is executed in a separate thread!
  1587.         """
  1588.         cups.setUser(self.connect_user)
  1589.         if self.connect_server[0] == '/':
  1590.             # UNIX domain socket.  This may potentially fail if the server
  1591.             # settings have been changed and cupsd has written out a
  1592.             # configuration that does not include a Listen line for the
  1593.             # UNIX domain socket.  To handle this special case, try to
  1594.             # connect once and fall back to "localhost" on failure.
  1595.             try:
  1596.                 connection = cups.Connection (host=self.connect_server,
  1597.                                               encryption=self.connect_encrypt)
  1598.  
  1599.                 # Worked fine.  Disconnect, and we'll connect for real
  1600.                 # shortly.
  1601.                 del connection
  1602.             except RuntimeError:
  1603.                 # When we connect, avoid the domain socket.
  1604.                 cups.setServer ("localhost")
  1605.             except:
  1606.                 nonfatalException ()
  1607.  
  1608.         try:
  1609.             connection = authconn.Connection(parent,
  1610.                                              host=self.connect_server,
  1611.                                              encryption=self.connect_encrypt)
  1612.             self.newPrinterGUI.dropPPDs ()
  1613.         except RuntimeError, s:
  1614.             if self.connect_thread != thread.get_ident(): return
  1615.             gtk.gdk.threads_enter()
  1616.             self.ConnectingDialog.hide()
  1617.             show_IPP_Error(None, s, parent)
  1618.             gtk.gdk.threads_leave()
  1619.             return
  1620.         except cups.IPPError, (e, s):
  1621.             if self.connect_thread != thread.get_ident(): return
  1622.             gtk.gdk.threads_enter()
  1623.             self.ConnectingDialog.hide()
  1624.             show_IPP_Error(e, s, parent)
  1625.             gtk.gdk.threads_leave()
  1626.             return
  1627.         except:
  1628.             nonfatalException ()
  1629.  
  1630.         if self.connect_thread != thread.get_ident(): return
  1631.         gtk.gdk.threads_enter()
  1632.  
  1633.         try:
  1634.             self.ConnectingDialog.hide()
  1635.             self.cups = connection
  1636.             self.setConnected()
  1637.             self.populateList()
  1638.     except cups.HTTPError, (s,):
  1639.             self.cups = None
  1640.             self.setConnected()
  1641.             self.populateList()
  1642.             show_HTTP_Error(s, parent)
  1643.         except:
  1644.             nonfatalException ()
  1645.  
  1646.         gtk.gdk.threads_leave()
  1647.  
  1648.     def reconnect (self):
  1649.         """Reconnect to CUPS after the server has reloaded."""
  1650.         # libcups would handle the reconnection if we just told it to
  1651.         # do something, for example fetching a list of classes.
  1652.         # However, our local authentication certificate would be
  1653.         # invalidated by a server restart, so it is better for us to
  1654.         # handle the reconnection ourselves.
  1655.  
  1656.         attempt = 1
  1657.         while attempt <= 5:
  1658.             try:
  1659.                 time.sleep(1)
  1660.                 self.cups._connect ()
  1661.                 break
  1662.             except RuntimeError:
  1663.                 # Connection failed.
  1664.                 attempt += 1
  1665.  
  1666.     def on_btnCancelConnect_clicked(self, widget):
  1667.         """Close Connect dialog"""
  1668.         self.ConnectWindow.hide()
  1669.  
  1670.     # refresh
  1671.  
  1672.     def on_btnRefresh_clicked(self, button):
  1673.         if self.cups == None:
  1674.             try:
  1675.                 self.cups = authconn.Connection(self.PrintersWindow)
  1676.             except RuntimeError:
  1677.                 pass
  1678.  
  1679.             self.setConnected()
  1680.  
  1681.         self.populateList()
  1682.  
  1683.     # Data handling
  1684.  
  1685.     def on_printer_changed(self, widget):
  1686.         if isinstance(widget, gtk.CheckButton):
  1687.             value = widget.get_active()
  1688.         elif isinstance(widget, gtk.Entry):
  1689.             value = widget.get_text()
  1690.         elif isinstance(widget, gtk.RadioButton):
  1691.             value = widget.get_active()
  1692.         elif isinstance(widget, gtk.ComboBox):
  1693.             model = widget.get_model ()
  1694.             iter = widget.get_active_iter()
  1695.             value = model.get_value (iter, 1)
  1696.         else:
  1697.             raise ValueError, "Widget type not supported (yet)"
  1698.  
  1699.         p = self.printer
  1700.         old_values = {
  1701.             self.entPDescription : p.info,
  1702.             self.entPLocation : p.location,
  1703.             self.entPDevice : p.device_uri,
  1704.             self.chkPEnabled : p.enabled,
  1705.             self.chkPAccepting : not p.rejecting,
  1706.             self.chkPShared : p.is_shared,
  1707.             self.cmbPStartBanner : p.job_sheet_start,
  1708.             self.cmbPEndBanner : p.job_sheet_end,
  1709.             self.cmbPErrorPolicy : p.error_policy,
  1710.             self.cmbPOperationPolicy : p.op_policy,
  1711.             self.rbtnPAllow: p.default_allow,
  1712.             }
  1713.  
  1714.         old_value = old_values[widget]
  1715.  
  1716.         if old_value == value:
  1717.             self.changed.discard(widget)
  1718.         else:
  1719.             self.changed.add(widget)
  1720.         self.setDataButtonState()
  1721.  
  1722.     def option_changed(self, option):
  1723.         if option.is_changed():
  1724.             self.changed.add(option)
  1725.         else:
  1726.             self.changed.discard(option)
  1727.  
  1728.         if option.conflicts:
  1729.             self.conflicts.add(option)
  1730.         else:
  1731.             self.conflicts.discard(option)
  1732.         self.setDataButtonState()
  1733.  
  1734.         if (self.option_manualfeed and self.option_inputslot and
  1735.             option == self.option_manualfeed):
  1736.             if option.get_current_value() == "True":
  1737.                 self.option_inputslot.disable ()
  1738.             else:
  1739.                 self.option_inputslot.enable ()
  1740.  
  1741.     # Access control
  1742.     def getPUsers(self):
  1743.         """return list of usernames from the GUI"""
  1744.         model = self.tvPUsers.get_model()
  1745.         result = []
  1746.         model.foreach(lambda model, path, iter:
  1747.                       result.append(model.get(iter, 0)[0]))
  1748.         result.sort()
  1749.         return result
  1750.  
  1751.     def setPUsers(self, users):
  1752.         """write list of usernames inot the GUI"""
  1753.         model = self.tvPUsers.get_model()
  1754.         model.clear()
  1755.         for user in users:
  1756.             model.append((user,))
  1757.  
  1758.         self.on_entPUser_changed(self.entPUser)
  1759.         self.on_tvPUsers_cursor_changed(self.tvPUsers)
  1760.  
  1761.     def checkPUsersChanged(self):
  1762.         """check if users in GUI and printer are different
  1763.         and set self.changed"""
  1764.         if self.getPUsers() != self.printer.except_users:
  1765.             self.changed.add(self.tvPUsers)
  1766.         else:
  1767.             self.changed.discard(self.tvPUsers)
  1768.  
  1769.         self.on_tvPUsers_cursor_changed(self.tvPUsers)
  1770.         self.setDataButtonState()
  1771.  
  1772.     def on_btnPAddUser_clicked(self, button):
  1773.         user = self.entPUser.get_text()
  1774.         if user:
  1775.             self.tvPUsers.get_model().insert(0, (user,))
  1776.             self.entPUser.set_text("")
  1777.         self.checkPUsersChanged()
  1778.  
  1779.     def on_btnPDelUser_clicked(self, button):
  1780.         model, rows = self.tvPUsers.get_selection().get_selected_rows()
  1781.         rows = [gtk.TreeRowReference(model, row) for row in rows]
  1782.         for row in rows:
  1783.             path = row.get_path()
  1784.             iter = model.get_iter(path)
  1785.             model.remove(iter)
  1786.         self.checkPUsersChanged()
  1787.  
  1788.     def on_entPUser_changed(self, widget):
  1789.         self.btnPAddUser.set_sensitive(bool(widget.get_text()))
  1790.  
  1791.     def on_tvPUsers_cursor_changed(self, widget):
  1792.         model, rows = widget.get_selection().get_selected_rows()
  1793.         self.btnPDelUser.set_sensitive(bool(rows))
  1794.  
  1795.     # Server side options
  1796.     def on_job_option_reset(self, button):
  1797.         option = self.job_options_buttons[button]
  1798.         option.reset ()
  1799.         # Remember to set this option for removal in the IPP request.
  1800.         if self.server_side_options.has_key (option.name):
  1801.             del self.server_side_options[option.name]
  1802.         if option.is_changed ():
  1803.             self.changed.add(option)
  1804.         else:
  1805.             self.changed.discard(option)
  1806.         self.setDataButtonState()
  1807.  
  1808.     def on_job_option_changed(self, widget):
  1809.         if not self.printer:
  1810.             return
  1811.         option = self.job_options_widgets[widget]
  1812.         option.changed ()
  1813.         if option.is_changed ():
  1814.             self.server_side_options[option.name] = option
  1815.             self.changed.add(option)
  1816.         else:
  1817.             if self.server_side_options.has_key (option.name):
  1818.                 del self.server_side_options[option.name]
  1819.             self.changed.discard(option)
  1820.         self.setDataButtonState()
  1821.         # Don't set the reset button insensitive if the option hasn't
  1822.         # changed from the original value: it's still meaningful to
  1823.         # reset the option to the system default.
  1824.  
  1825.     def draw_other_job_options (self, editable=True):
  1826.         n = len (self.other_job_options)
  1827.         if n == 0:
  1828.             self.tblJOOther.hide_all ()
  1829.             return
  1830.  
  1831.         self.tblJOOther.resize (n, 3)
  1832.         children = self.tblJOOther.get_children ()
  1833.         for child in children:
  1834.             self.tblJOOther.remove (child)
  1835.         i = 0
  1836.         for opt in self.other_job_options:
  1837.             self.tblJOOther.attach (opt.label, 0, 1, i, i + 1,
  1838.                                     xoptions=gtk.FILL,
  1839.                                     yoptions=gtk.FILL)
  1840.             opt.label.set_alignment (0.0, 0.5)
  1841.             self.tblJOOther.attach (opt.selector, 1, 2, i, i + 1,
  1842.                                     xoptions=gtk.FILL,
  1843.                                     yoptions=0)
  1844.             opt.selector.set_sensitive (editable)
  1845.  
  1846.             btn = gtk.Button(stock="gtk-remove")
  1847.             btn.connect("clicked", self.on_btnJOOtherRemove_clicked)
  1848.             btn.set_data("pyobject", opt)
  1849.             btn.set_sensitive (editable)
  1850.             self.tblJOOther.attach(btn, 2, 3, i, i + 1,
  1851.                                    xoptions=0,
  1852.                                    yoptions=0)
  1853.             i += 1
  1854.  
  1855.         self.tblJOOther.show_all ()
  1856.  
  1857.     def add_job_option(self, name, value = "", supported = "", is_new=True,
  1858.                        editable=True):
  1859.         option = options.OptionWidget(name, value, supported,
  1860.                                       self.option_changed)
  1861.         option.is_new = is_new
  1862.         self.other_job_options.append (option)
  1863.         self.draw_other_job_options (editable=editable)
  1864.         self.server_side_options[name] = option
  1865.         if name in self.changed: # was deleted before
  1866.             option.is_new = False
  1867.         self.changed.add(option)
  1868.         self.setDataButtonState()
  1869.         if is_new:
  1870.             option.selector.grab_focus ()
  1871.  
  1872.     def on_btnJOOtherRemove_clicked(self, button):
  1873.         option = button.get_data("pyobject")
  1874.         self.other_job_options.remove (option)
  1875.         self.draw_other_job_options ()
  1876.         if option.is_new:
  1877.             self.changed.discard(option)
  1878.         else:
  1879.             # keep name as reminder that option got deleted
  1880.             self.changed.add(option.name)
  1881.         del self.server_side_options[option.name]
  1882.         self.setDataButtonState()
  1883.  
  1884.     def on_btnNewJobOption_clicked(self, button):
  1885.         name = self.entNewJobOption.get_text()
  1886.         self.add_job_option(name)
  1887.         self.tblJOOther.show_all()
  1888.         self.entNewJobOption.set_text ('')
  1889.         self.btnNewJobOption.set_sensitive (False)
  1890.         self.setDataButtonState()
  1891.  
  1892.     def on_entNewJobOption_changed(self, widget):
  1893.         text = self.entNewJobOption.get_text()
  1894.         active = (len(text) > 0) and text not in self.server_side_options
  1895.         self.btnNewJobOption.set_sensitive(active)
  1896.  
  1897.     def on_entNewJobOption_activate(self, widget):
  1898.         self.on_btnNewJobOption_clicked (widget) # wrong widget but ok
  1899.  
  1900.     # set buttons sensitivity
  1901.     def setDataButtonState(self):
  1902.         try: # Might not be a printer selected
  1903.             possible = (self.ppd and
  1904.                         not bool (self.changed) and
  1905.                         self.printer.enabled and
  1906.                         not self.printer.rejecting)
  1907.  
  1908.             for button in [self.btnPrintTestPage,
  1909.                            self.btnChangePPD,
  1910.                            self.btnSelectDevice]:
  1911.                 button.set_sensitive (possible)
  1912.  
  1913.             commands = (self.printer.type & cups.CUPS_PRINTER_COMMANDS) != 0
  1914.             self.btnSelfTest.set_sensitive (commands and possible)
  1915.             self.btnCleanHeads.set_sensitive (commands and possible)
  1916.         except:
  1917.             pass
  1918.  
  1919.         installablebold = False
  1920.         optionsbold = False
  1921.         if self.conflicts:
  1922.             debugprint ("Conflicts detected")
  1923.             self.btnConflict.show()
  1924.             for option in self.conflicts:
  1925.                 if option.tab_label == self.lblPInstallOptions:
  1926.                     installablebold = True
  1927.                 else:
  1928.                     optionsbold = True
  1929.         else:
  1930.             self.btnConflict.hide()
  1931.         installabletext = _("Installable Options")
  1932.         optionstext = _("Printer Options")
  1933.         if installablebold:
  1934.             installabletext = "<b>%s</b>" % installabletext
  1935.         if optionsbold:
  1936.             optionstext = "<b>%s</b>" % optionstext
  1937.         self.lblPInstallOptions.set_markup (installabletext)
  1938.         self.lblPOptions.set_markup (optionstext)
  1939.  
  1940.         store = self.tvPrinterProperties.get_model ()
  1941.         if store:
  1942.             for n in range (self.ntbkPrinter.get_n_pages ()):
  1943.                 page = self.ntbkPrinter.get_nth_page (n)
  1944.                 label = self.ntbkPrinter.get_tab_label (page)
  1945.                 try:
  1946.                     if label == self.lblPInstallOptions:
  1947.                         iter = store.get_iter ((n,))
  1948.                         store.set_value (iter, 0, installabletext)
  1949.                     elif label == self.lblPOptions:
  1950.                         iter = store.get_iter ((n,))
  1951.                         store.set_value (iter, 0, optionstext)
  1952.                 except ValueError:
  1953.                     # If we get here, the store has not yet been set
  1954.                     # up (trac #111).
  1955.                     pass
  1956.  
  1957.         self.btnPrinterPropertiesApply.set_sensitive (len (self.changed) > 0 and
  1958.                                                       not self.conflicts)
  1959.         self.btnPrinterPropertiesOK.set_sensitive (len (self.changed) > 0 and
  1960.                                                    not self.conflicts)
  1961.  
  1962.     def save_printer(self, printer, saveall=False, parent=None):
  1963.         if parent == None:
  1964.             parent = self.PrinterPropertiesDialog
  1965.         class_deleted = False
  1966.         name = printer.name
  1967.  
  1968.         if printer.is_class:
  1969.             self.cups._begin_operation (_("modifying class %s") % name)
  1970.         else:
  1971.             self.cups._begin_operation (_("modifying printer %s") % name)
  1972.  
  1973.         try:
  1974.             if not printer.is_class and self.ppd:
  1975.                 self.getPrinterSettings()
  1976.                 if self.ppd.nondefaultsMarked() or saveall:
  1977.                     self.cups.addPrinter(name, ppd=self.ppd)
  1978.  
  1979.             if printer.is_class:
  1980.                 # update member list
  1981.                 new_members = getCurrentClassMembers(self.tvClassMembers)
  1982.                 if not new_members:
  1983.                     dialog = gtk.MessageDialog(
  1984.                         flags=0, type=gtk.MESSAGE_WARNING,
  1985.                         buttons=gtk.BUTTONS_YES_NO,
  1986.                         message_format=_("This will delete this class!"))
  1987.                     dialog.format_secondary_text(_("Proceed anyway?"))
  1988.                     result = dialog.run()
  1989.                     dialog.destroy()
  1990.                     if result==gtk.RESPONSE_NO:
  1991.                         self.cups._end_operation ()
  1992.                         return True
  1993.                     class_deleted = True
  1994.  
  1995.                 # update member list
  1996.                 old_members = printer.class_members[:]
  1997.  
  1998.                 for member in new_members:
  1999.                     if member in old_members:
  2000.                         old_members.remove(member)
  2001.                     else:
  2002.                         self.cups.addPrinterToClass(member, name)
  2003.                 for member in old_members:
  2004.                     self.cups.deletePrinterFromClass(member, name)
  2005.  
  2006.             location = self.entPLocation.get_text()
  2007.             info = self.entPDescription.get_text()
  2008.             device_uri = self.entPDevice.get_text()
  2009.  
  2010.             enabled = self.chkPEnabled.get_active()
  2011.             accepting = self.chkPAccepting.get_active()
  2012.             shared = self.chkPShared.get_active()
  2013.  
  2014.             if info!=printer.info or saveall:
  2015.                 self.cups.setPrinterInfo(name, info)
  2016.             if location!=printer.location or saveall:
  2017.                 self.cups.setPrinterLocation(name, location)
  2018.             if (not printer.is_class and
  2019.                 (device_uri!=printer.device_uri or saveall)):
  2020.                 self.cups.setPrinterDevice(name, device_uri)
  2021.  
  2022.             if enabled != printer.enabled or saveall:
  2023.                 self.printer.setEnabled(enabled)
  2024.             if accepting == printer.rejecting or saveall:
  2025.                 self.printer.setAccepting(accepting)
  2026.             if shared != printer.is_shared or saveall:
  2027.                 self.printer.setShared(shared)
  2028.  
  2029.             def get_combo_value (cmb):
  2030.                 model = cmb.get_model ()
  2031.                 iter = cmb.get_active_iter ()
  2032.                 return model.get_value (iter, 1)
  2033.  
  2034.             job_sheet_start = get_combo_value (self.cmbPStartBanner)
  2035.             job_sheet_end = get_combo_value (self.cmbPEndBanner)
  2036.             error_policy = get_combo_value (self.cmbPErrorPolicy)
  2037.             op_policy = get_combo_value (self.cmbPOperationPolicy)
  2038.  
  2039.             if (job_sheet_start != printer.job_sheet_start or
  2040.                 job_sheet_end != printer.job_sheet_end) or saveall:
  2041.                 printer.setJobSheets(job_sheet_start, job_sheet_end)
  2042.             if error_policy != printer.error_policy or saveall:
  2043.                 printer.setErrorPolicy(error_policy)
  2044.             if op_policy != printer.op_policy or saveall:
  2045.                 printer.setOperationPolicy(op_policy)
  2046.  
  2047.             default_allow = self.rbtnPAllow.get_active()
  2048.             except_users = self.getPUsers()
  2049.  
  2050.             if (default_allow != printer.default_allow or
  2051.                 except_users != printer.except_users) or saveall:
  2052.                 printer.setAccess(default_allow, except_users)
  2053.  
  2054.             for option in printer.attributes:
  2055.                 if option not in self.server_side_options:
  2056.                     printer.unsetOption(option)
  2057.             for option in self.server_side_options.itervalues():
  2058.                 if (option.is_changed() or
  2059.                     saveall and
  2060.                     option.get_current_value () != option.system_default):
  2061.                     printer.setOption(option.name, option.get_current_value())
  2062.  
  2063.         except cups.IPPError, (e, s):
  2064.             show_IPP_Error(e, s, parent)
  2065.             self.cups._end_operation ()
  2066.             return True
  2067.         self.cups._end_operation ()
  2068.         self.changed = set() # of options
  2069.  
  2070.         if not self.cups._use_pk and not self.__dict__.has_key ("server_settings"):
  2071.             # We can authenticate with the server correctly at this point,
  2072.             # but we have never fetched the server settings to see whether
  2073.             # the server is publishing shared printers.  Fetch the settings
  2074.             # now so that we can update the "not published" label if necessary.
  2075.             self.cups._begin_operation (_("fetching server settings"))
  2076.             try:
  2077.                 self.server_settings = self.cups.adminGetServerSettings()
  2078.             except:
  2079.                 nonfatalException()
  2080.  
  2081.             self.cups._end_operation ()
  2082.  
  2083.         if class_deleted:
  2084.             self.monitor.update ()
  2085.         else:
  2086.             # Update our copy of the printer's settings.
  2087.             self.cups._begin_operation (_("obtaining queue details"))
  2088.             try:
  2089.                 printers = cupshelpers.getPrinters (self.cups)
  2090.                 this_printer = { name: printers[name] }
  2091.                 self.printers.update (this_printer)
  2092.             except cups.IPPError, (e, s):
  2093.                 show_IPP_Error(e, s, self.PrinterPropertiesDialog)
  2094.             except KeyError:
  2095.                 # The printer was deleted in the mean time and the
  2096.                 # user made no changes.
  2097.                 self.populateList ()
  2098.  
  2099.             self.cups._end_operation ()
  2100.         return False
  2101.  
  2102.     def getPrinterSettings(self):
  2103.         #self.ppd.markDefaults()
  2104.         for option in self.options.itervalues():
  2105.             option.writeback()
  2106.  
  2107.     ### Printer Properties tree view signal handlers
  2108.     def on_tvPrinterProperties_selection_changed (self, selection):
  2109.         # Prevent selection from being de-selected.
  2110.         (model, iter) = selection.get_selected ()
  2111.         if iter:
  2112.             self.printer_properties_last_iter_selected = iter
  2113.         else:
  2114.             try:
  2115.                 iter = self.printer_properties_last_iter_selected
  2116.             except AttributeError:
  2117.                 # Not set yet.
  2118.                 return
  2119.  
  2120.             if model.iter_is_valid (iter):
  2121.                 selection.select_iter (iter)
  2122.  
  2123.     def on_tvPrinterProperties_cursor_changed (self, treeview):
  2124.         # Adjust notebook to reflect selected item.
  2125.         (path, column) = treeview.get_cursor ()
  2126.         if path != None:
  2127.             model = treeview.get_model ()
  2128.             iter = model.get_iter (path)
  2129.             n = model.get_value (iter, 1)
  2130.             self.ntbkPrinter.set_current_page (n)
  2131.  
  2132.     # set default printer
  2133.     def set_system_or_user_default_printer (self, name):
  2134.         # First, decide if this is already the system default, in which
  2135.         # case we only need to clear the user default.
  2136.         userdef = userdefault.UserDefaultPrinter ()
  2137.         if name == self.default_printer:
  2138.             userdef.clear ()
  2139.             self.populateList ()
  2140.             return
  2141.  
  2142.         userdefault.UserDefaultPrompt (self.set_default_printer,
  2143.                                        self.populateList,
  2144.                                        name,
  2145.                                        _("Set Default Printer"),
  2146.                                        self.PrintersWindow,
  2147.                                        _("Do you want to set this as "
  2148.                                          "the system-wide default printer?"),
  2149.                                        _("Set as the _system-wide "
  2150.                                          "default printer"),
  2151.                                        _("_Clear my personal default setting"),
  2152.                                        _("Set as my _personal default printer"))
  2153.  
  2154.     def set_default_printer (self, name):
  2155.         printer = self.printers[name]
  2156.         reload = False
  2157.         self.cups._begin_operation (_("setting default printer"))
  2158.         try:
  2159.             reload = printer.setAsDefault ()
  2160.         except cups.HTTPError, (s,):
  2161.             show_HTTP_Error (s, self.PrintersWindow)
  2162.             self.cups._end_operation ()
  2163.             return
  2164.         except cups.IPPError, (e, msg):
  2165.             show_IPP_Error(e, msg, self.PrintersWindow)
  2166.             self.cups._end_operation ()
  2167.             return
  2168.  
  2169.         self.cups._end_operation ()
  2170.  
  2171.         # Now reconnect in case the server needed to reload.  This may
  2172.         # happen if we replaced the lpoptions file.
  2173.         if reload:
  2174.             self.reconnect ()
  2175.  
  2176.         try:
  2177.             self.populateList()
  2178.         except cups.HTTPError, (s,):
  2179.             self.cups = None
  2180.             self.setConnected()
  2181.             self.populateList()
  2182.             show_HTTP_Error(s, self.PrintersWindow)
  2183.  
  2184.     # print test page
  2185.  
  2186.     def on_btnPrintTestPage_clicked(self, button):
  2187.         if self.ppd == False:
  2188.             # Can't print a test page for a raw queue.
  2189.             return
  2190.  
  2191.         # if we have a page size specific custom test page, use it;
  2192.         # otherwise use cups' default one
  2193.         custom_testpage = None
  2194.         if self.ppd != False:
  2195.             opt = self.ppd.findOption ("PageSize")
  2196.             if opt:
  2197.                 custom_testpage = os.path.join(pkgdata,
  2198.                                                'testpage-%s.ps' %
  2199.                                                opt.defchoice.lower())
  2200.  
  2201.         # Connect as the current user so that the test page can be managed
  2202.         # as a normal job.
  2203.         user = cups.getUser ()
  2204.         cups.setUser ('')
  2205.         try:
  2206.             c = authconn.Connection (self.PrintersWindow, try_as_root=False,
  2207.                                      host=self.connect_server,
  2208.                                      encryption=self.connect_encrypt)
  2209.         except RuntimeError, s:
  2210.             show_IPP_Error (None, s, self.PrintersWindow)
  2211.             return
  2212.  
  2213.         job_id = None
  2214.         c._begin_operation (_("printing test page"))
  2215.         try:
  2216.             if custom_testpage and os.path.exists(custom_testpage):
  2217.                 debugprint ('Printing custom test page ' + custom_testpage)
  2218.                 job_id = c.printTestPage(self.printer.name,
  2219.                                          file=custom_testpage)
  2220.             else:
  2221.                 debugprint ('Printing default test page')
  2222.                 job_id = c.printTestPage(self.printer.name)
  2223.         except cups.IPPError, (e, msg):
  2224.             if (e == cups.IPP_NOT_AUTHORIZED and
  2225.                 self.connect_server != 'localhost' and
  2226.                 self.connect_server[0] != '/'):
  2227.                 show_error_dialog (_("Not possible"),
  2228.                                    _("The remote server did not accept "
  2229.                                      "the print job, most likely "
  2230.                                      "because the printer is not "
  2231.                                      "shared."),
  2232.                                    self.PrintersWindow)
  2233.             else:
  2234.                 show_IPP_Error(e, msg, self.PrintersWindow)
  2235.  
  2236.         c._end_operation ()
  2237.         cups.setUser (user)
  2238.  
  2239.         if job_id != None:
  2240.             show_info_dialog (_("Submitted"),
  2241.                               _("Test page submitted as job %d") % job_id,
  2242.                               parent=self.PrintersWindow)
  2243.  
  2244.     def maintenance_command (self, command):
  2245.         (tmpfd, tmpfname) = tempfile.mkstemp ()
  2246.         os.write (tmpfd, "#CUPS-COMMAND\n%s\n" % command)
  2247.         os.close (tmpfd)
  2248.         self.cups._begin_operation (_("sending maintenance command"))
  2249.         try:
  2250.             format = "application/vnd.cups-command"
  2251.             job_id = self.cups.printTestPage (self.printer.name,
  2252.                                               format=format,
  2253.                                               file=tmpfname,
  2254.                                               user=self.connect_user)
  2255.             show_info_dialog (_("Submitted"),
  2256.                               _("Maintenance command submitted as "
  2257.                                 "job %d") % job_id,
  2258.                               parent=self.PrintersWindow)
  2259.         except cups.IPPError, (e, msg):
  2260.             if (e == cups.IPP_NOT_AUTHORIZED and
  2261.                 self.printer.name != 'localhost'):
  2262.                 show_error_dialog (_("Not possible"),
  2263.                                    _("The remote server did not accept "
  2264.                                      "the print job, most likely "
  2265.                                      "because the printer is not "
  2266.                                      "shared."),
  2267.                                    self.PrintersWindow)
  2268.             else:
  2269.                 show_IPP_Error(e, msg, self.PrintersWindow)
  2270.  
  2271.         self.cups._end_operation ()
  2272.  
  2273.         os.unlink (tmpfname)
  2274.  
  2275.     def on_btnSelfTest_clicked(self, button):
  2276.         self.maintenance_command ("PrintSelfTestPage")
  2277.  
  2278.     def on_btnCleanHeads_clicked(self, button):
  2279.         self.maintenance_command ("Clean all")
  2280.  
  2281.     def fillComboBox(self, combobox, values, value, translationdict=None):
  2282.         if translationdict == None:
  2283.             translationdict = ppdippstr.TranslactionDict ()
  2284.  
  2285.         model = gtk.ListStore (gobject.TYPE_STRING,
  2286.                                gobject.TYPE_STRING)
  2287.         combobox.set_model (model)
  2288.         set_active = False
  2289.         for nr, val in enumerate(values):
  2290.             model.append ([(translationdict.get (val)), val])
  2291.             if val == value:
  2292.                 combobox.set_active(nr)
  2293.                 set_active = True
  2294.  
  2295.         if not set_active:
  2296.             combobox.set_active (0)
  2297.  
  2298.     def fillPrinterTab(self, name):
  2299.         self.changed = set() # of options
  2300.         self.options = {} # keyword -> Option object
  2301.         self.conflicts = set() # of options
  2302.  
  2303.         printer = self.printers[name]
  2304.         self.printer = printer
  2305.         printer.getAttributes ()
  2306.         try:
  2307.             # CUPS 1.4
  2308.             publishing = printer.other_attributes['server-is-sharing-printers']
  2309.             self.server_is_publishing = publishing
  2310.         except KeyError:
  2311.             pass
  2312.  
  2313.         editable = not self.printer.discovered
  2314.         editablePPD = not self.printer.remote
  2315.  
  2316.         try:
  2317.             self.ppd = printer.getPPD()
  2318.             self.ppd_local = printer.getPPD()
  2319.             if self.ppd_local != False:
  2320.                 self.ppd_local.localize()
  2321.         except cups.IPPError, (e, m):
  2322.             # Some IPP error other than IPP_NOT_FOUND.
  2323.             show_IPP_Error(e, m, self.PrintersWindow)
  2324.             # Treat it as a raw queue.
  2325.             self.ppd = False
  2326.         except RuntimeError:
  2327.             # The underlying cupsGetPPD2() function returned NULL without
  2328.             # setting an IPP error, so it'll be something like a failed
  2329.             # connection.
  2330.             show_error_dialog (_("Error"),
  2331.                                _("There was a problem connecting to "
  2332.                                  "the CUPS server."),
  2333.                                self.PrintersWindow)
  2334.             raise
  2335.  
  2336.         for widget in (self.entPDescription, self.entPLocation,
  2337.                        self.entPDevice):
  2338.             widget.set_editable(editable)
  2339.  
  2340.         for widget in (self.btnSelectDevice, self.btnChangePPD,
  2341.                        self.chkPEnabled, self.chkPAccepting, self.chkPShared,
  2342.                        self.cmbPStartBanner, self.cmbPEndBanner,
  2343.                        self.cmbPErrorPolicy, self.cmbPOperationPolicy,
  2344.                        self.rbtnPAllow, self.rbtnPDeny, self.tvPUsers,
  2345.                        self.entPUser, self.btnPAddUser, self.btnPDelUser):
  2346.             widget.set_sensitive(editable)
  2347.  
  2348.         # Description page
  2349.         self.entPDescription.set_text(printer.info)
  2350.         self.entPLocation.set_text(printer.location)
  2351.  
  2352.         uri = printer.device_uri
  2353.         self.entPDevice.set_text(uri)
  2354.         self.changed.discard(self.entPDevice)
  2355.  
  2356.         # Hide make/model and Device URI for classes
  2357.         for widget in (self.lblPMakeModel2, self.lblPMakeModel,
  2358.                        self.btnChangePPD, self.lblPDevice2,
  2359.                        self.entPDevice, self.btnSelectDevice):
  2360.             if printer.is_class:
  2361.                 widget.hide()
  2362.             else:
  2363.                 widget.show()
  2364.  
  2365.  
  2366.         # Policy tab
  2367.         # ----------
  2368.  
  2369.         try:
  2370.             if printer.is_shared:
  2371.                 if self.server_is_publishing:
  2372.                     self.lblNotPublished.hide_all ()
  2373.                 else:
  2374.                     self.lblNotPublished.show_all ()
  2375.             else:
  2376.                 self.lblNotPublished.hide_all ()
  2377.         except:
  2378.             nonfatalException()
  2379.             self.lblNotPublished.hide_all ()
  2380.  
  2381.         # Job sheets
  2382.         self.cmbPStartBanner.set_sensitive(editable)
  2383.         self.cmbPEndBanner.set_sensitive(editable)
  2384.  
  2385.         # Policies
  2386.         self.cmbPErrorPolicy.set_sensitive(editable)
  2387.         self.cmbPOperationPolicy.set_sensitive(editable)
  2388.  
  2389.         # Access control
  2390.         self.entPUser.set_text("")
  2391.  
  2392.         # Server side options (Job options)
  2393.         self.server_side_options = {}
  2394.         for option in self.job_options_widgets.values ():
  2395.             if option.name == "media" and self.ppd:
  2396.                 # Slightly special case because the 'system default'
  2397.                 # (i.e. what you get when you press Reset) depends
  2398.                 # on the printer's PageSize.
  2399.                 opt = self.ppd.findOption ("PageSize")
  2400.                 if opt:
  2401.                     option.set_default (opt.defchoice)
  2402.  
  2403.             option_editable = editable
  2404.             try:
  2405.                 value = self.printer.attributes[option.name]
  2406.             except KeyError:
  2407.                 option.reinit (None)
  2408.             else:
  2409.                 try:
  2410.                     if self.printer.possible_attributes.has_key (option.name):
  2411.                         supported = self.printer.\
  2412.                                     possible_attributes[option.name][1]
  2413.                         # Set the option widget.
  2414.                         # In CUPS 1.3.x the orientation-requested-default
  2415.                         # attribute may have the value None; this means there
  2416.                         # is no value set.  This suits our needs here, as None
  2417.                         # resets the option to the system default and makes the
  2418.                         # Reset button insensitive.
  2419.                         option.reinit (value, supported=supported)
  2420.                     else:
  2421.                         option.reinit (value)
  2422.  
  2423.                     self.server_side_options[option.name] = option
  2424.                 except:
  2425.                     option_editable = False
  2426.                     show_error_dialog (_("Error"),
  2427.                                        _("Option '%s' has value '%s' "
  2428.                                          "and cannot be edited.") %
  2429.                                        (option.name, value),
  2430.                                        self.PrintersWindow)
  2431.             option.widget.set_sensitive (option_editable)
  2432.             if not editable:
  2433.                 option.button.set_sensitive (False)
  2434.         self.other_job_options = []
  2435.         self.draw_other_job_options (editable=editable)
  2436.         for option in self.printer.attributes.keys ():
  2437.             if self.server_side_options.has_key (option):
  2438.                 continue
  2439.             value = self.printer.attributes[option]
  2440.             if self.printer.possible_attributes.has_key (option):
  2441.                 supported = self.printer.possible_attributes[option][1]
  2442.             else:
  2443.                 if isinstance (value, bool):
  2444.                     supported = ["true", "false"]
  2445.                     value = str (value).lower ()
  2446.                 else:
  2447.                     supported = ""
  2448.                     value = str (value)
  2449.  
  2450.             self.add_job_option (option, value=value,
  2451.                                  supported=supported, is_new=False,
  2452.                                  editable=editable)
  2453.         self.entNewJobOption.set_text ('')
  2454.         self.entNewJobOption.set_sensitive (editable)
  2455.         self.btnNewJobOption.set_sensitive (False)
  2456.  
  2457.         if printer.is_class:
  2458.             # remove InstallOptions tab
  2459.             tab_nr = self.ntbkPrinter.page_num(self.swPInstallOptions)
  2460.             if tab_nr != -1:
  2461.                 self.ntbkPrinter.remove_page(tab_nr)
  2462.             self.fillClassMembers(name, editable)
  2463.         else:
  2464.             # real Printer
  2465.             self.fillPrinterOptions(name, editablePPD)
  2466.  
  2467.         self.updateMarkerLevels()
  2468.         self.updateStateReasons()
  2469.         self.updatePrinterPropertiesTreeView()
  2470.  
  2471.         self.changed = set() # of options
  2472.         self.updatePrinterProperties ()
  2473.         self.setDataButtonState()
  2474.  
  2475.     def updatePrinterPropertiesTreeView (self):
  2476.         # Now update the tree view (which we use instead of the notebook tabs).
  2477.         store = gtk.ListStore (gobject.TYPE_STRING, gobject.TYPE_INT)
  2478.         self.ntbkPrinter.set_show_tabs (False)
  2479.         for n in range (self.ntbkPrinter.get_n_pages ()):
  2480.             page = self.ntbkPrinter.get_nth_page (n)
  2481.             label = self.ntbkPrinter.get_tab_label (page)
  2482.             iter = store.append (None)
  2483.             store.set_value (iter, 0, label.get_text ())
  2484.             store.set_value (iter, 1, n)
  2485.         sel = self.tvPrinterProperties.get_selection ()
  2486.         self.tvPrinterProperties.set_model (store)
  2487.  
  2488.     def updateMarkerLevels (self):
  2489.         printer = self.printer
  2490.  
  2491.         # Marker levels
  2492.         for widget in self.vboxMarkerLevels.get_children ():
  2493.             self.vboxMarkerLevels.remove (widget)
  2494.  
  2495.         marker_info = dict()
  2496.         for attr in ['marker-colors', 'marker-names', 'marker-types',
  2497.                      'marker-levels']:
  2498.             val = printer.other_attributes.get (attr, [])
  2499.             if type (val) != list:
  2500.                 # Work around bug fixed in pycups 1.9.46.
  2501.                 val = [val]
  2502.  
  2503.             marker_info[attr] = val
  2504.  
  2505.  
  2506.         markers = map (lambda color, name, type, level:
  2507.                            (color, name, type, level),
  2508.                        marker_info['marker-colors'],
  2509.                        marker_info['marker-names'],
  2510.                        marker_info['marker-types'],
  2511.                        marker_info['marker-levels'])
  2512.         debugprint (markers)
  2513.  
  2514.         can_refresh = (self.printer.type & cups.CUPS_PRINTER_COMMANDS) != 0
  2515.         self.btnRefreshMarkerLevels.set_sensitive (can_refresh)
  2516.         if len (markers) == 0:
  2517.             label = gtk.Label(_("Marker levels are not reported "
  2518.                                 "for this printer."))
  2519.             label.set_line_wrap (True)
  2520.             label.set_alignment (0.0, 0.0)
  2521.             self.vboxMarkerLevels.pack_start (label, False, False, 0)
  2522.         else:
  2523.             num_markers = 0
  2524.             cols = len (markers)
  2525.             rows = 1 + (cols - 1) / 4
  2526.             if cols > 4:
  2527.                 cols = 4
  2528.             table = gtk.Table (rows=rows,
  2529.                                columns=cols,
  2530.                                homogeneous=True)
  2531.             table.set_col_spacings (6)
  2532.             table.set_row_spacings (12)
  2533.             self.vboxMarkerLevels.pack_start (table)
  2534.             for color, name, marker_type, level in markers:
  2535.                 if name == None:
  2536.                     name = ''
  2537.                 else:
  2538.                     ppd = printer.getPPD()
  2539.                     if ppd != False:
  2540.                         localized_name = ppd.localizeMarkerName(name)
  2541.                         if localized_name != None:
  2542.                             name = localized_name
  2543.  
  2544.                 row = num_markers / 4
  2545.                 col = num_markers % 4
  2546.  
  2547.                 vbox = gtk.VBox (spacing=6)
  2548.                 subhbox = gtk.HBox ()
  2549.                 inklevel = gtkinklevel.GtkInkLevel (color, level)
  2550.                 subhbox.pack_start (inklevel, True, False, 0)
  2551.                 vbox.pack_start (subhbox, False, False, 0)
  2552.                 label = gtk.Label (name)
  2553.                 label.set_line_wrap (True)
  2554.                 vbox.pack_start (label, False, False, 0)
  2555.                 table.attach (vbox, col, col + 1, row, row + 1)
  2556.                 num_markers += 1
  2557.  
  2558.         self.vboxMarkerLevels.show_all ()
  2559.  
  2560.     def on_btnRefreshMarkerLevels_clicked (self, button):
  2561.         self.maintenance_command ("ReportLevels")
  2562.  
  2563.     def updateStateReasons (self):
  2564.         printer = self.printer
  2565.         reasons = printer.other_attributes.get ('printer-state-reasons', [])
  2566.         store = gtk.ListStore (str, str)
  2567.         any = False
  2568.         for reason in reasons:
  2569.             if reason == "none":
  2570.                 break
  2571.  
  2572.             any = True
  2573.             iter = store.append (None)
  2574.             r = statereason.StateReason (printer.name, reason)
  2575.             if r.get_reason () == "paused":
  2576.                 icon = gtk.STOCK_MEDIA_PAUSE
  2577.             else:
  2578.                 icon = statereason.StateReason.LEVEL_ICON[r.get_level ()]
  2579.             store.set_value (iter, 0, icon)
  2580.             (title, text) = r.get_description ()
  2581.             store.set_value (iter, 1, text)
  2582.  
  2583.         self.tvPrinterStateReasons.set_model (store)
  2584.         page = 0
  2585.         if any:
  2586.             page = 1
  2587.  
  2588.         self.ntbkPrinterStateReasons.set_current_page (page)
  2589.  
  2590.     def set_printer_state_reason_icon (self, column, cell, model, iter, *data):
  2591.         icon = model.get_value (iter, 0)
  2592.         theme = gtk.icon_theme_get_default ()
  2593.         try:
  2594.             pixbuf = theme.load_icon (icon, 22, 0)
  2595.             cell.set_property ("pixbuf", pixbuf)
  2596.         except gobject.GError, exc:
  2597.             pass # Couldn't load icon
  2598.  
  2599.     def set_printer_state_reason_text (self, column, cell, model, iter, *data):
  2600.         cell.set_property ("text", model.get_value (iter, 1))
  2601.  
  2602.     def updatePrinterProperties(self):
  2603.         debugprint ("update printer properties")
  2604.         printer = self.printer
  2605.         self.lblPMakeModel.set_text(printer.make_and_model)
  2606.         state = self.printer_states.get (printer.state, _("Unknown"))
  2607.         reason = printer.other_attributes.get ('printer-state-message', '')
  2608.         if len (reason) > 0:
  2609.             state += ' - ' + reason
  2610.         self.lblPState.set_text(state)
  2611.         if len (self.changed) == 0:
  2612.             debugprint ("no changes yet: full printer properties update")
  2613.             # State
  2614.             self.chkPEnabled.set_active(printer.enabled)
  2615.             self.chkPAccepting.set_active(not printer.rejecting)
  2616.             self.chkPShared.set_active(printer.is_shared)
  2617.  
  2618.             # Job sheets
  2619.             self.fillComboBox(self.cmbPStartBanner,
  2620.                               printer.job_sheets_supported,
  2621.                               printer.job_sheet_start,
  2622.                               ppdippstr.job_sheets)
  2623.             self.fillComboBox(self.cmbPEndBanner, printer.job_sheets_supported,
  2624.                               printer.job_sheet_end,
  2625.                               ppdippstr.job_sheets)
  2626.  
  2627.             # Policies
  2628.             self.fillComboBox(self.cmbPErrorPolicy,
  2629.                               printer.error_policy_supported,
  2630.                               printer.error_policy,
  2631.                               ppdippstr.printer_error_policy)
  2632.             self.fillComboBox(self.cmbPOperationPolicy,
  2633.                               printer.op_policy_supported,
  2634.                               printer.op_policy,
  2635.                               ppdippstr.printer_op_policy)
  2636.  
  2637.             # Access control
  2638.             self.rbtnPAllow.set_active(printer.default_allow)
  2639.             self.rbtnPDeny.set_active(not printer.default_allow)
  2640.             self.setPUsers(printer.except_users)
  2641.  
  2642.             # Marker levels
  2643.             self.updateMarkerLevels ()
  2644.             self.updateStateReasons ()
  2645.  
  2646.             self.updatePrinterPropertiesTreeView ()
  2647.  
  2648.     def fillPrinterOptions(self, name, editable):
  2649.         # remove Class membership tab
  2650.         tab_nr = self.ntbkPrinter.page_num(self.algnClassMembers)
  2651.         if tab_nr != -1:
  2652.             self.ntbkPrinter.remove_page(tab_nr)
  2653.  
  2654.         # clean Installable Options Tab
  2655.         for widget in self.vbPInstallOptions.get_children():
  2656.             self.vbPInstallOptions.remove(widget)
  2657.  
  2658.         # clean Options Tab
  2659.         for widget in self.vbPOptions.get_children():
  2660.             self.vbPOptions.remove(widget)
  2661.  
  2662.         # insert Options Tab
  2663.         if self.ntbkPrinter.page_num(self.swPOptions) == -1:
  2664.             self.ntbkPrinter.insert_page(
  2665.                 self.swPOptions, self.lblPOptions, self.static_tabs)
  2666.  
  2667.         if not self.ppd:
  2668.             tab_nr = self.ntbkPrinter.page_num(self.swPInstallOptions)
  2669.             if tab_nr != -1:
  2670.                 self.ntbkPrinter.remove_page(tab_nr)
  2671.             tab_nr = self.ntbkPrinter.page_num(self.swPOptions)
  2672.             if tab_nr != -1:
  2673.                 self.ntbkPrinter.remove_page(tab_nr)
  2674.             return
  2675.         ppd = self.ppd
  2676.         ppd.markDefaults()
  2677.         self.ppd_local.markDefaults()
  2678.  
  2679.         hasInstallableOptions = False
  2680.  
  2681.         # build option tabs
  2682.         for group in self.ppd_local.optionGroups:
  2683.             if group.name == "InstallableOptions":
  2684.                 hasInstallableOptions = True
  2685.                 container = self.vbPInstallOptions
  2686.                 tab_nr = self.ntbkPrinter.page_num(self.swPInstallOptions)
  2687.                 if tab_nr == -1:
  2688.                     self.ntbkPrinter.insert_page(self.swPInstallOptions,
  2689.                                                  gtk.Label(group.text),
  2690.                                                  self.static_tabs)
  2691.                 tab_label = self.lblPInstallOptions
  2692.             else:
  2693.                 frame = gtk.Frame("<b>%s</b>" % ppdippstr.ppd.get (group.text))
  2694.                 frame.get_label_widget().set_use_markup(True)
  2695.                 frame.set_shadow_type (gtk.SHADOW_NONE)
  2696.                 self.vbPOptions.pack_start (frame, False, False, 0)
  2697.                 container = gtk.Alignment (0.5, 0.5, 1.0, 1.0)
  2698.                 # We want a left padding of 12, but there is a Table with
  2699.                 # spacing 6, and the left-most column of it (the conflict
  2700.                 # icon) is normally hidden, so just use 6 here.
  2701.                 container.set_padding (6, 12, 6, 0)
  2702.                 frame.add (container)
  2703.                 tab_label = self.lblPOptions
  2704.  
  2705.             table = gtk.Table(1, 3, False)
  2706.             table.set_col_spacings(6)
  2707.             table.set_row_spacings(6)
  2708.             container.add(table)
  2709.  
  2710.             rows = 0
  2711.  
  2712.             # InputSlot and ManualFeed need special handling.  With
  2713.             # libcups, if ManualFeed is True, InputSlot gets unset.
  2714.             # Likewise, if InputSlot is set, ManualFeed becomes False.
  2715.             # We handle it by toggling the sensitivity of InputSlot
  2716.             # based on ManualFeed.
  2717.             self.option_inputslot = self.option_manualfeed = None
  2718.  
  2719.             for nr, option in enumerate(group.options):
  2720.                 if option.keyword == "PageRegion":
  2721.                     continue
  2722.                 rows += 1
  2723.                 table.resize (rows, 3)
  2724.                 o = OptionWidget(option, ppd, self, tab_label=tab_label)
  2725.                 table.attach(o.conflictIcon, 0, 1, nr, nr+1, 0, 0, 0, 0)
  2726.  
  2727.                 hbox = gtk.HBox()
  2728.                 if o.label:
  2729.                     a = gtk.Alignment (0.5, 0.5, 1.0, 1.0)
  2730.                     a.set_padding (0, 0, 0, 6)
  2731.                     a.add (o.label)
  2732.                     table.attach(a, 1, 2, nr, nr+1, gtk.FILL, 0, 0, 0)
  2733.                     table.attach(hbox, 2, 3, nr, nr+1, gtk.FILL, 0, 0, 0)
  2734.                 else:
  2735.                     table.attach(hbox, 1, 3, nr, nr+1, gtk.FILL, 0, 0, 0)
  2736.                 hbox.pack_start(o.selector, False)
  2737.                 self.options[option.keyword] = o
  2738.                 o.selector.set_sensitive(editable)
  2739.                 if option.keyword == "InputSlot":
  2740.                     self.option_inputslot = o
  2741.                 elif option.keyword == "ManualFeed":
  2742.                     self.option_manualfeed = o
  2743.  
  2744.         # remove Installable Options tab if not needed
  2745.         if not hasInstallableOptions:
  2746.             tab_nr = self.ntbkPrinter.page_num(self.swPInstallOptions)
  2747.             if tab_nr != -1:
  2748.                 self.ntbkPrinter.remove_page(tab_nr)
  2749.  
  2750.         # check for conflicts
  2751.         for option in self.options.itervalues():
  2752.             conflicts = option.checkConflicts()
  2753.             if conflicts:
  2754.                 self.conflicts.add(option)
  2755.  
  2756.         self.swPInstallOptions.show_all()
  2757.         self.swPOptions.show_all()
  2758.  
  2759.     # Class members
  2760.  
  2761.     def fillClassMembers(self, name, editable):
  2762.         printer = self.printers[name]
  2763.  
  2764.         self.btnClassAddMember.set_sensitive(editable)
  2765.         self.btnClassDelMember.set_sensitive(editable)
  2766.  
  2767.         # remove Options tab
  2768.         tab_nr = self.ntbkPrinter.page_num(self.swPOptions)
  2769.         if tab_nr != -1:
  2770.             self.ntbkPrinter.remove_page(tab_nr)
  2771.  
  2772.         # insert Member Tab
  2773.         if self.ntbkPrinter.page_num(self.algnClassMembers) == -1:
  2774.             self.ntbkPrinter.insert_page(
  2775.                 self.algnClassMembers, self.lblClassMembers,
  2776.                 self.static_tabs)
  2777.  
  2778.         model_members = self.tvClassMembers.get_model()
  2779.         model_not_members = self.tvClassNotMembers.get_model()
  2780.         model_members.clear()
  2781.         model_not_members.clear()
  2782.  
  2783.         names = self.printers.keys()
  2784.         names.sort()
  2785.         for name in names:
  2786.             p = self.printers[name]
  2787.             if p is not printer:
  2788.                 if name in printer.class_members:
  2789.                     model_members.append((name, ))
  2790.                 else:
  2791.                     model_not_members.append((name, ))
  2792.  
  2793.     def on_btnClassAddMember_clicked(self, button):
  2794.         moveClassMembers(self.tvClassNotMembers,
  2795.                          self.tvClassMembers)
  2796.         if getCurrentClassMembers(self.tvClassMembers) != self.printer.class_members:
  2797.             self.changed.add(self.tvClassMembers)
  2798.         else:
  2799.             self.changed.discard(self.tvClassMembers)
  2800.         self.setDataButtonState()
  2801.  
  2802.     def on_btnClassDelMember_clicked(self, button):
  2803.         moveClassMembers(self.tvClassMembers,
  2804.                          self.tvClassNotMembers)
  2805.         if getCurrentClassMembers(self.tvClassMembers) != self.printer.class_members:
  2806.             self.changed.add(self.tvClassMembers)
  2807.         else:
  2808.             self.changed.discard(self.tvClassMembers)
  2809.         self.setDataButtonState()
  2810.  
  2811.     # Quit
  2812.  
  2813.     def on_quit_activate(self, widget, event=None):
  2814.         self.monitor.cleanup ()
  2815.         while len (self.jobviewers) > 0:
  2816.             self.jobviewers[0].cleanup () # this will call on_jobviewer_exit
  2817.         del self.mainlist
  2818.         del self.printers
  2819.         gtk.main_quit()
  2820.  
  2821.     # Rename
  2822.     def is_rename_possible (self, name):
  2823.         jobs = self.printers[name].jobsQueued (limit=1)
  2824.         if len (jobs) > 0:
  2825.             show_error_dialog (_("Cannot Rename"),
  2826.                                _("There are queued jobs."),
  2827.                                parent=self.PrintersWindow)
  2828.             return False
  2829.  
  2830.         return True
  2831.  
  2832.     def rename_confirmed_by_user (self, name):
  2833.         """
  2834.         Renaming deletes job history. So if we have some completed jobs,
  2835.         inform the user and let him confirm the renaming.
  2836.         """
  2837.         preserved_jobs = self.printers[name].jobsPreserved(limit=1)
  2838.         if len (preserved_jobs) > 0:
  2839.             dialog = gtk.MessageDialog (self.PrintersWindow,
  2840.                                         gtk.DIALOG_MODAL |
  2841.                                         gtk.DIALOG_DESTROY_WITH_PARENT,
  2842.                                         gtk.MESSAGE_WARNING,
  2843.                                         gtk.BUTTONS_OK_CANCEL,
  2844.                                         _("Renaming will lose history"))
  2845.  
  2846.             dialog.format_secondary_text (_("Completed jobs will no longer "
  2847.                                             "be available for re-printing."))
  2848.             result = dialog.run()
  2849.             dialog.destroy ()
  2850.             if result == gtk.RESPONSE_CANCEL:
  2851.                 return False
  2852.  
  2853.         return True
  2854.  
  2855.     def on_rename_activate(self, UNUSED):
  2856.         tuple = self.dests_iconview.get_cursor ()
  2857.         if tuple == None:
  2858.             return
  2859.  
  2860.         (path, cell) = tuple
  2861.         if type (cell) != gtk.CellRendererText:
  2862.             cells = self.dests_iconview.get_cells ()
  2863.             for cell in cells:
  2864.                 if type (cell) == gtk.CellRendererText:
  2865.                     break
  2866.             if type (cell) != gtk.CellRendererText:
  2867.                 return
  2868.  
  2869.         model = self.dests_iconview.get_model ()
  2870.         iter = model.get_iter (path)
  2871.         name = unicode (model.get_value (iter, 2))
  2872.         if not self.is_rename_possible (name):
  2873.             return
  2874.         if not self.rename_confirmed_by_user (name):
  2875.             return
  2876.         cell.set_property ('editable', True)
  2877.         self.dests_iconview.set_cursor (path, cell, start_editing=True)
  2878.         ids = []
  2879.         ids.append (cell.connect ('edited', self.printer_name_edited))
  2880.         ids.append (cell.connect ('editing-canceled',
  2881.                                  self.printer_name_edit_cancel))
  2882.         self.rename_sigids = ids
  2883.  
  2884.     def printer_name_edited (self, cell, path, newname):
  2885.         model = self.dests_iconview.get_model ()
  2886.         iter = model.get_iter (path)
  2887.         name = unicode (model.get_value (iter, 2))
  2888.         debugprint ("edited: %s -> %s" % (name, newname))
  2889.         try:
  2890.             self.rename_printer (name, newname)
  2891.         finally:
  2892.             cell.stop_editing (canceled=False)
  2893.             cell.set_property ('editable', False)
  2894.             for id in self.rename_sigids:
  2895.                 cell.disconnect (id)
  2896.  
  2897.     def printer_name_edit_cancel (self, cell):
  2898.         debugprint ("editing-canceled")
  2899.         cell.stop_editing (canceled=True)
  2900.         cell.set_property ('editable', False)
  2901.         for id in self.rename_sigids:
  2902.             cell.disconnect (id)
  2903.  
  2904.     def rename_printer (self, old_name, new_name):
  2905.         if old_name == new_name:
  2906.             return
  2907.  
  2908.         try:
  2909.             self.fillPrinterTab (old_name)
  2910.         except RuntimeError:
  2911.             # Perhaps cupsGetPPD2 failed for a browsed printer
  2912.             pass
  2913.  
  2914.         if not self.is_rename_possible (old_name):
  2915.             return
  2916.  
  2917.         self.cups._begin_operation (_("renaming printer"))
  2918.         rejecting = self.printer.rejecting
  2919.         if not rejecting:
  2920.             try:
  2921.                 self.printer.setAccepting (False)
  2922.                 if not self.is_rename_possible (old_name):
  2923.                     self.printer.setAccepting (True)
  2924.                     self.cups._end_operation ()
  2925.                     return
  2926.             except cups.IPPError, (e, msg):
  2927.                 show_IPP_Error (e, msg, self.PrintersWindow)
  2928.                 self.cups._end_operation ()
  2929.                 return
  2930.  
  2931.         if self.copy_printer (new_name):
  2932.             # Failure.
  2933.             self.monitor.update ()
  2934.  
  2935.             # Restore original accepting/rejecting state.
  2936.             if not rejecting:
  2937.                 try:
  2938.                     self.printers[old_name].setAccepting (True)
  2939.                 except cups.HTTPError, (s,):
  2940.                     show_HTTP_Error (s, self.PrintersWindow)
  2941.                 except cups.IPPError, (e, msg):
  2942.                     show_IPP_Error (e, msg, self.PrintersWindow)
  2943.  
  2944.             self.cups._end_operation ()
  2945.             return
  2946.  
  2947.         # Restore rejecting state.
  2948.         if not rejecting:
  2949.             try:
  2950.                 self.printer.setAccepting (True)
  2951.             except cups.HTTPError, (s,):
  2952.                 show_HTTP_Error (s, self.PrintersWindow)
  2953.                 # Not fatal.
  2954.             except cups.IPPError, (e, msg):
  2955.                 show_IPP_Error (e, msg, self.PrintersWindow)
  2956.                 # Not fatal.
  2957.  
  2958.         # Fix up default printer.
  2959.         if self.default_printer == old_name:
  2960.             reload = False
  2961.             try:
  2962.                 reload = self.printer.setAsDefault ()
  2963.             except cups.HTTPError, (s,):
  2964.                 show_HTTP_Error (s, self.PrintersWindow)
  2965.                 # Not fatal.
  2966.             except cups.IPPError, (e, msg):
  2967.                 show_IPP_Error (e, msg, self.PrintersWindow)
  2968.                 # Not fatal.
  2969.  
  2970.             if reload:
  2971.                 self.reconnect ()
  2972.  
  2973.         # Finally, delete the old printer.
  2974.         try:
  2975.             self.cups.deletePrinter (old_name)
  2976.         except cups.HTTPError, (s,):
  2977.             show_HTTP_Error (s, self.PrintersWindow)
  2978.             # Not fatal
  2979.         except cups.IPPError, (e, msg):
  2980.             show_IPP_Error (e, msg, self.PrintersWindow)
  2981.             # Not fatal.
  2982.  
  2983.         self.cups._end_operation ()
  2984.  
  2985.         # ..and select the new printer.
  2986.         def select_new_printer (model, path, iter):
  2987.             name = unicode (model.get_value (iter, 2))
  2988.             print name, new_name
  2989.             if name == new_name:
  2990.                 self.dests_iconview.select_path (path)
  2991.         self.populateList ()
  2992.         model = self.dests_iconview.get_model ()
  2993.         model.foreach (select_new_printer)
  2994.  
  2995.     # Copy
  2996.  
  2997.     def copy_printer (self, new_name):
  2998.         self.printer.name = new_name
  2999.         self.printer.class_members = [] # for classes make sure all members
  3000.                                         # will get added
  3001.  
  3002.         self.cups._begin_operation (_("copying printer"))
  3003.         ret = self.save_printer(self.printer, saveall=True,
  3004.                                 parent=self.PrintersWindow)
  3005.         self.cups._end_operation ()
  3006.         return ret
  3007.  
  3008.     def on_copy_activate(self, UNUSED):
  3009.         iconview = self.dests_iconview
  3010.         paths = iconview.get_selected_items ()
  3011.         model = self.dests_iconview.get_model ()
  3012.         iter = model.get_iter (paths[0])
  3013.         name = unicode (model.get_value (iter, 2))
  3014.         self.entCopyName.set_text(name)
  3015.         self.NewPrinterName.set_transient_for (self.PrintersWindow)
  3016.         result = self.NewPrinterName.run()
  3017.         self.NewPrinterName.hide()
  3018.  
  3019.         if result == gtk.RESPONSE_CANCEL:
  3020.             return
  3021.  
  3022.         try:
  3023.             self.fillPrinterTab (name)
  3024.         except RuntimeError:
  3025.             # Perhaps cupsGetPPD2 failed for a browsed printer
  3026.             pass
  3027.  
  3028.         self.copy_printer (self.entCopyName.get_text ())
  3029.         self.monitor.update ()
  3030.  
  3031.     def on_entCopyName_changed(self, widget):
  3032.         # restrict
  3033.         text = unicode (widget.get_text())
  3034.         new_text = text
  3035.         new_text = new_text.replace("/", "")
  3036.         new_text = new_text.replace("#", "")
  3037.         new_text = new_text.replace(" ", "")
  3038.         if text!=new_text:
  3039.             widget.set_text(new_text)
  3040.         self.btnCopyOk.set_sensitive(
  3041.             self.checkNPName(new_text))
  3042.  
  3043.     # Delete
  3044.  
  3045.     def on_delete_activate(self, UNUSED):
  3046.         if isinstance (self.current_groups_pane_item, StaticGroupItem):
  3047.             paths = self.dests_iconview.get_selected_items ()
  3048.             model = self.dests_iconview.get_model ()
  3049.             selected_names = []
  3050.             for path in paths:
  3051.                 selected_names.append (model[path][2])
  3052.             self.current_groups_pane_item.remove_queues (selected_names)
  3053.             self.populateList ()
  3054.         else:
  3055.             self.delete_selected_printer_queues ()
  3056.  
  3057.     def delete_selected_printer_queues (self):
  3058.         paths = self.dests_iconview.get_selected_items ()
  3059.         model = self.dests_iconview.get_model ()
  3060.         n = len (paths)
  3061.         if n == 1:
  3062.             iter = model.get_iter (paths[0])
  3063.             object = model.get_value (iter, 0)
  3064.             name = model.get_value (iter, 2)
  3065.             if object.is_class:
  3066.                 message_format = _("Really delete class '%s'?") % name
  3067.             else:
  3068.                 message_format = _("Really delete printer '%s'?") % name
  3069.         else:
  3070.             message_format = _("Really delete selected destinations?")
  3071.  
  3072.         dialog = gtk.MessageDialog(self.PrintersWindow,
  3073.                                    gtk.DIALOG_DESTROY_WITH_PARENT |
  3074.                                    gtk.DIALOG_MODAL,
  3075.                                    gtk.MESSAGE_WARNING,
  3076.                                    gtk.BUTTONS_NONE,
  3077.                                    message_format)
  3078.         dialog.add_buttons (gtk.STOCK_CANCEL, gtk.RESPONSE_REJECT,
  3079.                             gtk.STOCK_DELETE, gtk.RESPONSE_ACCEPT)
  3080.         dialog.set_default_response (gtk.RESPONSE_REJECT)
  3081.         result = dialog.run()
  3082.         dialog.destroy()
  3083.  
  3084.         if result != gtk.RESPONSE_ACCEPT:
  3085.             return
  3086.  
  3087.         try:
  3088.             for path in paths:
  3089.                 iter = model.get_iter (path)
  3090.                 name = model.get_value (iter, 2)
  3091.                 self.cups._begin_operation (_("deleting printer %s") % name)
  3092.                 name = unicode (name)
  3093.                 self.cups.deletePrinter (name)
  3094.                 self.cups._end_operation ()
  3095.         except cups.IPPError, (e, msg):
  3096.             self.cups._end_operation ()
  3097.             show_IPP_Error(e, msg, self.PrintersWindow)
  3098.  
  3099.         self.changed = set()
  3100.         self.monitor.update ()
  3101.  
  3102.     # Enable/disable
  3103.     def on_enabled_activate(self, toggle_action):
  3104.         if self.updating_widgets:
  3105.             return
  3106.         enable = toggle_action.get_active ()
  3107.         iconview = self.dests_iconview
  3108.         paths = iconview.get_selected_items ()
  3109.         model = iconview.get_model ()
  3110.         for path in paths:
  3111.             iter = model.get_iter (path)
  3112.             printer = model.get_value (iter, 0)
  3113.             name = unicode (model.get_value (iter, 2), 'utf-8')
  3114.             self.cups._begin_operation (_("modifying printer %s") % name)
  3115.             try:
  3116.                 printer.setEnabled (enable)
  3117.             except cups.IPPError, (e, m):
  3118.                 errordialogs.show_IPP_Error (e, m, self.PrintersWindow)
  3119.                 # Give up on this operation.
  3120.                 self.cups._end_operation ()
  3121.                 break
  3122.  
  3123.             self.cups._end_operation ()
  3124.  
  3125.         self.monitor.update ()
  3126.  
  3127.     # Shared
  3128.     def on_shared_activate(self, menuitem):
  3129.         if self.updating_widgets:
  3130.             return
  3131.         share = menuitem.get_active ()
  3132.         iconview = self.dests_iconview
  3133.         paths = iconview.get_selected_items ()
  3134.         model = iconview.get_model ()
  3135.         success = False
  3136.         for path in paths:
  3137.             iter = model.get_iter (path)
  3138.             printer = model.get_value (iter, 0)
  3139.             self.cups._begin_operation (_("modifying printer %s") %
  3140.                                         printer.name)
  3141.             try:
  3142.                 printer.setShared (share)
  3143.                 success = True
  3144.             except cups.IPPError, (e, m):
  3145.                 show_IPP_Error(e, m, self.PrintersWindow)
  3146.                 self.cups._end_operation ()
  3147.                 # Give up on this operation.
  3148.                 break
  3149.  
  3150.             self.cups._end_operation ()
  3151.  
  3152.         if success and share:
  3153.             self.advise_publish ()
  3154.  
  3155.         # For some reason CUPS doesn't give us a notification about
  3156.         # printers changing 'shared' state, so refresh instead of
  3157.         # update.  We have to defer this to prevent signal problems.
  3158.         def deferred_refresh ():
  3159.             self.populateList ()
  3160.             return False
  3161.         gobject.idle_add (deferred_refresh)
  3162.  
  3163.     def advise_publish(self):
  3164.         if not self.server_is_publishing:
  3165.             show_info_dialog (_("Publish Shared Printers"),
  3166.                               _("Shared printers are not available "
  3167.                                 "to other people unless the "
  3168.                                 "'Publish shared printers' option is "
  3169.                                 "enabled in the server settings."),
  3170.                               parent=self.PrintersWindow)
  3171.  
  3172.     # Set As Default
  3173.     def on_set_as_default_activate(self, UNUSED):
  3174.         iconview = self.dests_iconview
  3175.         paths = iconview.get_selected_items ()
  3176.         model = iconview.get_model ()
  3177.         iter = model.get_iter (paths[0])
  3178.         name = unicode (model.get_value (iter, 2))
  3179.         self.set_system_or_user_default_printer (name)
  3180.  
  3181.     def on_edit_activate (self, UNUSED):
  3182.         paths = self.dests_iconview.get_selected_items ()
  3183.         self.dests_iconview_item_activated (self.dests_iconview, paths[0])
  3184.  
  3185.     def on_create_class_activate (self, UNUSED):
  3186.         paths = self.dests_iconview.get_selected_items ()
  3187.         class_members = []
  3188.         model = self.dests_iconview.get_model ()
  3189.         for path in paths:
  3190.             iter = model.get_iter (path)
  3191.             name = unicode (model.get_value (iter, 2), 'utf-8')
  3192.             class_members.append (name)
  3193.         self.newPrinterGUI.init ("class")
  3194.         out_model = self.newPrinterGUI.tvNCNotMembers.get_model ()
  3195.         in_model = self.newPrinterGUI.tvNCMembers.get_model ()
  3196.         iter = out_model.get_iter_first ()
  3197.         while iter != None:
  3198.             next = out_model.iter_next (iter)
  3199.             data = out_model.get (iter, 0)
  3200.             if data[0] in class_members:
  3201.                 in_model.append (data)
  3202.                 out_model.remove (iter)
  3203.             iter = next
  3204.  
  3205.     def on_view_print_queue_activate (self, UNUSED):
  3206.         paths = self.dests_iconview.get_selected_items ()
  3207.         if len (paths):
  3208.             specific_dests = []
  3209.             model = self.dests_iconview.get_model ()
  3210.             for path in paths:
  3211.                 iter = model.get_iter (path)
  3212.                 name = unicode (model.get_value (iter, 2), 'utf-8')
  3213.                 specific_dests.append (name)
  3214.             viewer = jobviewer.JobViewer (None, None, my_jobs=False,
  3215.                                           specific_dests=specific_dests,
  3216.                                           exit_handler=self.on_jobviewer_exit,
  3217.                                           parent=self.PrintersWindow)
  3218.         else:
  3219.             viewer = jobviewer.JobViewer (None, None, my_jobs=False,
  3220.                                           exit_handler=self.on_jobviewer_exit,
  3221.                                           parent=self.PrintersWindow)
  3222.  
  3223.         self.jobviewers.append (viewer)
  3224.  
  3225.     def on_jobviewer_exit (self, viewer):
  3226.         i = self.jobviewers.index (viewer)
  3227.         del self.jobviewers[i]
  3228.  
  3229.     def on_view_groups_activate (self, widget):
  3230.         if widget.get_active ():
  3231.             if not self.groups_pane_visible:
  3232.                 # Show it.
  3233.                 self.view_area_vbox.remove (self.view_area_scrolledwindow)
  3234.                 self.view_area_hpaned.add2 (self.view_area_scrolledwindow)
  3235.                 self.view_area_vbox.add (self.view_area_hpaned)
  3236.                 self.view_area_vbox.show_all ()
  3237.                 self.groups_pane_visible = True
  3238.         else:
  3239.             if self.groups_pane_visible:
  3240.                 # Hide it.
  3241.                 self.view_area_vbox.remove (self.view_area_hpaned)
  3242.                 self.view_area_hpaned.remove (self.view_area_scrolledwindow)
  3243.                 self.view_area_vbox.add (self.view_area_scrolledwindow)
  3244.                 self.view_area_vbox.show_all ()
  3245.                 self.groups_pane_visible = False
  3246.  
  3247.     def on_view_discovered_printers_activate (self, UNUSED):
  3248.         self.populateList ()
  3249.  
  3250.     def on_troubleshoot_activate(self, widget):
  3251.         if not self.__dict__.has_key ('troubleshooter'):
  3252.             self.troubleshooter = troubleshoot.run (self.on_troubleshoot_quit)
  3253.  
  3254.     def on_troubleshoot_quit(self, troubleshooter):
  3255.         del self.troubleshooter
  3256.  
  3257.     def on_save_as_group_activate (self, UNUSED):
  3258.         model = self.dests_iconview.get_model ()
  3259.         printer_queues = []
  3260.         for object in model:
  3261.             printer_queues.append (object[2])
  3262.         self.groups_pane.create_new_group (printer_queues,
  3263.                                            self.current_filter_text)
  3264.  
  3265.     def on_save_as_search_group_activate (self, UNUSED):
  3266.         criterion = None
  3267.         if self.current_filter_mode == "filter-name":
  3268.             criterion = SearchCriterion (subject = SearchCriterion.SUBJECT_NAME,
  3269.                                          value   = self.current_filter_text)
  3270.         elif self.current_filter_mode == "filter-description":
  3271.             criterion = SearchCriterion (subject = SearchCriterion.SUBJECT_DESC,
  3272.                                          value   = self.current_filter_text)
  3273.         elif self.current_filter_mode == "filter-location":
  3274.             criterion = SearchCriterion (subject = SearchCriterion.SUBJECT_LOCATION,
  3275.                                          value   = self.current_filter_text)
  3276.         elif self.current_filter_mode == "filter-manufacturer":
  3277.             criterion = SearchCriterion (subject = SearchCriterion.SUBJECT_MANUF,
  3278.                                          value   = self.current_filter_text)
  3279.         else:
  3280.             nonfatalException ()
  3281.             return
  3282.  
  3283.         self.groups_pane.create_new_search_group (criterion,
  3284.                                                   self.current_filter_text)
  3285.  
  3286.     # About dialog
  3287.     def on_about_activate(self, widget):
  3288.         self.AboutDialog.set_transient_for (self.PrintersWindow)
  3289.         self.AboutDialog.run()
  3290.         self.AboutDialog.hide()
  3291.  
  3292.     ##########################################################################
  3293.     ### Server settings
  3294.     ##########################################################################
  3295.  
  3296.     def fillServerTab(self):
  3297.         self.changed = set()
  3298.         self.cups._begin_operation (_("fetching server settings"))
  3299.         try:
  3300.             self.server_settings = self.cups.adminGetServerSettings()
  3301.         except cups.IPPError, (e, m):
  3302.             show_IPP_Error(e, m, self.PrintersWindow)
  3303.             self.cups._end_operation ()
  3304.             raise
  3305.  
  3306.         self.cups._end_operation ()
  3307.  
  3308.         for widget, setting in [
  3309.             (self.chkServerBrowse, cups.CUPS_SERVER_REMOTE_PRINTERS),
  3310.             (self.chkServerShare, cups.CUPS_SERVER_SHARE_PRINTERS),
  3311.             (self.chkServerShareAny, try_CUPS_SERVER_REMOTE_ANY),
  3312.             (self.chkServerRemoteAdmin, cups.CUPS_SERVER_REMOTE_ADMIN),
  3313.             (self.chkServerAllowCancelAll, cups.CUPS_SERVER_USER_CANCEL_ANY),
  3314.             (self.chkServerLogDebug, cups.CUPS_SERVER_DEBUG_LOGGING),]:
  3315.             widget.set_data("setting", setting)
  3316.             if self.server_settings.has_key(setting):
  3317.                 widget.set_active(int(self.server_settings[setting]))
  3318.                 widget.set_sensitive(True)
  3319.             else:
  3320.                 widget.set_active(False)
  3321.                 widget.set_sensitive(False)
  3322.         self.setDataButtonState()
  3323.  
  3324.         try:
  3325.             flag = cups.CUPS_SERVER_SHARE_PRINTERS
  3326.             publishing = int (self.server_settings[flag])
  3327.             self.server_is_publishing = publishing
  3328.         except AttributeError:
  3329.             pass
  3330.  
  3331.         # Set sensitivity of 'Allow printing from the Internet'.
  3332.         self.on_server_changed (self.chkServerShare) # (any will do here)
  3333.  
  3334.     def on_server_changed(self, widget):
  3335.         setting = widget.get_data("setting")
  3336.         if self.server_settings.has_key (setting):
  3337.             if str(int(widget.get_active())) == self.server_settings[setting]:
  3338.                 self.changed.discard(widget)
  3339.             else:
  3340.                 self.changed.add(widget)
  3341.  
  3342.         sharing = self.chkServerShare.get_active ()
  3343.         self.chkServerShareAny.set_sensitive (
  3344.             sharing and self.server_settings.has_key(try_CUPS_SERVER_REMOTE_ANY))
  3345.  
  3346.         self.setDataButtonState()
  3347.  
  3348.     def save_serversettings(self):
  3349.         setting_dict = self.server_settings.copy()
  3350.         for widget, setting in [
  3351.             (self.chkServerBrowse, cups.CUPS_SERVER_REMOTE_PRINTERS),
  3352.             (self.chkServerShare, cups.CUPS_SERVER_SHARE_PRINTERS),
  3353.             (self.chkServerShareAny, try_CUPS_SERVER_REMOTE_ANY),
  3354.             (self.chkServerRemoteAdmin, cups.CUPS_SERVER_REMOTE_ADMIN),
  3355.             (self.chkServerAllowCancelAll, cups.CUPS_SERVER_USER_CANCEL_ANY),
  3356.             (self.chkServerLogDebug, cups.CUPS_SERVER_DEBUG_LOGGING),]:
  3357.             if not self.server_settings.has_key(setting): continue
  3358.             setting_dict[setting] = str(int(widget.get_active()))
  3359.         self.cups._begin_operation (_("modifying server settings"))
  3360.         try:
  3361.             self.cups.adminSetServerSettings(setting_dict)
  3362.         except cups.IPPError, (e, m):
  3363.             show_IPP_Error(e, m, self.ServerSettingsDialog)
  3364.             self.cups._end_operation ()
  3365.             return True
  3366.         except RuntimeError, s:
  3367.             show_IPP_Error(None, s, self.ServerSettingsDialog)
  3368.             self.cups._end_operation ()
  3369.             return True
  3370.         self.cups._end_operation ()
  3371.         self.changed = set()
  3372.         self.setDataButtonState()
  3373.  
  3374.         old_setting = self.server_settings.get (cups.CUPS_SERVER_SHARE_PRINTERS,
  3375.                                                 '0')
  3376.         new_setting = setting_dict.get (cups.CUPS_SERVER_SHARE_PRINTERS, '0')
  3377.         if (0 and old_setting == '0' and new_setting != '0'):
  3378.             # We have just enabled print queue sharing.
  3379.             # Ideally, this is the time we would check the firewall
  3380.             # settings on this machine and request that the IPP TCP port
  3381.             # be unblocked.  Unfortunately, this is not yet possible
  3382.             # (bug #440469).  However, we can display a dialog to suggest
  3383.             # that now might be a good time to review the firewall settings.
  3384.             show_info_dialog (_("Review Firewall"),
  3385.                               _("You may need to adjust the firewall "
  3386.                                 "to allow network printing to this "
  3387.                                 "computer.") + '\n\n' +
  3388.                               TEXT_start_firewall_tool,
  3389.                               parent=self.ServerSettingsDialog)
  3390.  
  3391.         time.sleep(1) # give the server a chance to process our request
  3392.  
  3393.         # Now reconnect, in case the server needed to reload.
  3394.         self.reconnect ()
  3395.  
  3396.         # Refresh the server settings in case they have changed in the
  3397.         # mean time.
  3398.         try:
  3399.             self.fillServerTab()
  3400.         except:
  3401.             nonfatalException()
  3402.  
  3403.     ### The "Problems?" clickable label
  3404.     def on_problems_button_clicked (self, *args):
  3405.         if not self.__dict__.has_key ('troubleshooter'):
  3406.             self.troubleshooter = troubleshoot.run (self.on_troubleshoot_quit,
  3407.                                                     parent=self.ServerSettingsDialog)
  3408.  
  3409.     # ====================================================================
  3410.     # == New Printer Dialog ==============================================
  3411.     # ====================================================================
  3412.  
  3413.     # new printer
  3414.     def on_new_printer_activate(self, widget):
  3415.         self.busy (self.PrintersWindow)
  3416.         self.newPrinterGUI.init("printer")
  3417.         self.ready (self.PrintersWindow)
  3418.  
  3419.     # new printer, auto-detected, but now driver found
  3420.     def on_autodetected_printer_without_driver(self, widget):
  3421.         self.busy (self.PrintersWindow)
  3422.         self.newPrinterGUI.init("printer_with_uri")
  3423.         self.ready (self.PrintersWindow)
  3424.  
  3425.     # new class
  3426.     def on_new_class_activate(self, widget):
  3427.         self.newPrinterGUI.init("class")
  3428.  
  3429.     # change device
  3430.     def on_btnSelectDevice_clicked(self, button):
  3431.         self.busy (self.PrintersWindow)
  3432.         self.newPrinterGUI.init("device")
  3433.         self.ready (self.PrintersWindow)
  3434.  
  3435.     # change PPD
  3436.     def on_btnChangePPD_clicked(self, button):
  3437.         self.busy (self.PrintersWindow)
  3438.         self.newPrinterGUI.init("ppd")
  3439.         self.ready (self.PrintersWindow)
  3440.  
  3441.     def checkNPName(self, name):
  3442.         if not name: return False
  3443.         name = unicode (name.lower())
  3444.         for printer in self.printers.values():
  3445.             if not printer.discovered and printer.name.lower()==name:
  3446.                 return False
  3447.         return True
  3448.  
  3449.     def makeNameUnique(self, name):
  3450.         """Make a suggested queue name valid and unique."""
  3451.         name = name.replace (" ", "-")
  3452.         name = name.replace ("/", "-")
  3453.         name = name.replace ("#", "-")
  3454.         if not self.checkNPName (name):
  3455.             suffix=2
  3456.             while not self.checkNPName (name + "-" + str (suffix)):
  3457.                 suffix += 1
  3458.                 if suffix == 100:
  3459.                     break
  3460.             name += "-" + str (suffix)
  3461.         return name
  3462.  
  3463.     ## Watcher interface helpers
  3464.     def printer_added_or_removed (self):
  3465.         # Just fetch the list of printers again.  This is too simplistic.
  3466.         gtk.gdk.threads_enter ()
  3467.         self.populateList (prompt_allowed=False)
  3468.         gtk.gdk.threads_leave ()
  3469.  
  3470.     ## Watcher interface
  3471.     def printer_added (self, mon, printer):
  3472.         monitor.Watcher.printer_added (self, mon, printer)
  3473.         self.printer_added_or_removed ()
  3474.  
  3475.     def printer_event (self, mon, printer, eventname, event):
  3476.         monitor.Watcher.printer_event (self, mon, printer, eventname, event)
  3477.  
  3478.         def deferred_refresh ():
  3479.             self.populateList ()
  3480.             return False
  3481.  
  3482.         gtk.gdk.threads_enter ()
  3483.         if self.printers.has_key (printer):
  3484.             self.printers[printer].update (**event)
  3485.             self.dests_iconview_selection_changed (self.dests_iconview)
  3486.             gobject.idle_add (deferred_refresh)
  3487.             if self.PrinterPropertiesDialog.get_property('visible'):
  3488.                 self.printer.getAttributes ()
  3489.                 self.updatePrinterProperties ()
  3490.  
  3491.         gtk.gdk.threads_leave ()
  3492.  
  3493.     def printer_removed (self, mon, printer):
  3494.         monitor.Watcher.printer_removed (self, mon, printer)
  3495.         self.printer_added_or_removed ()
  3496.  
  3497.     def state_reason_added (self, mon, reason):
  3498.         monitor.Watcher.state_reason_added (self, mon, reason)
  3499.         gtk.gdk.threads_enter ()
  3500.         if self.PrinterPropertiesDialog.get_property('visible'):
  3501.             self.printer.getAttributes ()
  3502.             self.updatePrinterProperties ()
  3503.  
  3504.         gtk.gdk.threads_leave ()
  3505.  
  3506.     def state_reason_removed (self, mon, reason):
  3507.         monitor.Watcher.state_reason_removed (self, mon, reason)
  3508.         gtk.gdk.threads_enter ()
  3509.         if self.PrinterPropertiesDialog.get_property('visible'):
  3510.             self.printer.getAttributes ()
  3511.             self.updatePrinterProperties ()
  3512.  
  3513.         gtk.gdk.threads_leave ()
  3514.  
  3515.     def cups_connection_error (self, mon):
  3516.         monitor.Watcher.cups_connection_error (self, mon)
  3517.         try:
  3518.             self.cups.getClasses ()
  3519.         except:
  3520.             self.cups = None
  3521.             gtk.gdk.threads_enter ()
  3522.             self.setConnected ()
  3523.             self.populateList (prompt_allowed=False)
  3524.             gtk.gdk.threads_leave ()
  3525.  
  3526. class NewPrinterGUI(GtkGUI):
  3527.  
  3528.     new_printer_device_tabs = {
  3529.         "parallel" : 0, # empty tab
  3530.         "usb" : 0,
  3531.         "bluetooth" : 0,
  3532.         "hal" : 0,
  3533.         "beh" : 0,
  3534.         "hp" : 0,
  3535.         "hpfax" : 0,
  3536.         "dnssd" : 0,
  3537.         "socket": 2,
  3538.         "ipp" : 3,
  3539.         "http" : 3,
  3540.         "https" : 3,
  3541.         "lpd" : 4,
  3542.         "scsi" : 5,
  3543.         "serial" : 6,
  3544.         "smb" : 7,
  3545.         "network": 8,
  3546.         }
  3547.  
  3548.     DOWNLOADABLE_ONLYPPD=True
  3549.     HP_PLUGIN_SUPPORT=True
  3550.  
  3551.     def __init__(self, mainapp):
  3552.         self.mainapp = mainapp
  3553.         self.language = mainapp.language
  3554.  
  3555.         self.options = {} # keyword -> Option object
  3556.         self.changed = set()
  3557.         self.conflicts = set()
  3558.         self.device = None
  3559.         self.ppd = None
  3560.         self.remotecupsqueue = False
  3561.         self.exactdrivermatch = False
  3562.         self.installable_options = False
  3563.         self.jockey_installed_files = []
  3564.  
  3565.         # Synchronisation objects.
  3566.         self.jockey_lock = thread.allocate_lock()
  3567.         self.ppds_lock = thread.allocate_lock()
  3568.         self.ppds_queried = False
  3569.         self.drivers_lock = thread.allocate_lock()
  3570.  
  3571.         self.getWidgets({"NewPrinterWindow":
  3572.                              ["NewPrinterWindow",
  3573.                               "ntbkNewPrinter",
  3574.                               "btnNPBack",
  3575.                               "btnNPForward",
  3576.                               "btnNPApply",
  3577.                               "imgProcessWorking",
  3578.                               "entNPName",
  3579.                               "entNPDescription",
  3580.                               "entNPLocation",
  3581.                               "tvNPDevices",
  3582.                               "ntbkNPType",
  3583.                               "lblNPDeviceDescription",
  3584.                               "expNPDeviceURIs",
  3585.                               "tvNPDeviceURIs",
  3586.                               "cmbNPTSerialBaud",
  3587.                               "cmbNPTSerialParity",
  3588.                               "cmbNPTSerialBits",
  3589.                               "cmbNPTSerialFlow",
  3590.                               "btnNPTLpdProbe",
  3591.                               "cmbentNPTLpdHost",
  3592.                               "cmbentNPTLpdQueue",
  3593.                               "entNPTIPPHostname",
  3594.                               "lblIPPURI",
  3595.                               "entNPTIPPQueuename",
  3596.                               "btnIPPVerify",
  3597.                               "entNPTDirectJetHostname",
  3598.                               "entNPTDirectJetPort",
  3599.                               "entSMBURI",
  3600.                               "btnSMBBrowse",
  3601.                               "tblSMBAuth",
  3602.                               "rbtnSMBAuthPrompt",
  3603.                               "rbtnSMBAuthSet",
  3604.                               "entSMBUsername",
  3605.                               "entSMBPassword",
  3606.                               "btnSMBVerify",
  3607.                               "entNPTNetworkHostname",
  3608.                               "btnNetworkFind",
  3609.                               "lblNetworkFindSearching",
  3610.                               "lblNetworkFindNotFound",
  3611.                               "entNPTDevice",
  3612.                               "tvNCMembers",
  3613.                               "tvNCNotMembers",
  3614.                               "btnNCAddMember",
  3615.                               "btnNCDelMember",
  3616.                               "ntbkPPDSource",
  3617.                               "rbtnNPPPD",
  3618.                               "tvNPMakes",
  3619.                               "rbtnNPFoomatic",
  3620.                               "filechooserPPD",
  3621.                               "rbtnNPDownloadableDriverSearch",
  3622.                               "entNPDownloadableDriverSearch",
  3623.                               "btnNPDownloadableDriverSearch",
  3624.                               "cmbNPDownloadableDriverFoundPrinters",
  3625.                               "tvNPModels",
  3626.                               "tvNPDrivers",
  3627.                               "rbtnChangePPDasIs",
  3628.                               "rbtnChangePPDKeepSettings",
  3629.                               "scrNPInstallableOptions",
  3630.                               "vbNPInstallOptions",
  3631.                               "tvNPDownloadableDrivers",
  3632.                               "ntbkNPDownloadableDriverProperties",
  3633.                               "lblNPDownloadableDriverSupplier",
  3634.                               "cbNPDownloadableDriverSupplierVendor",
  3635.                               "lblNPDownloadableDriverLicense",
  3636.                               "cbNPDownloadableDriverLicensePatents",
  3637.                               "cbNPDownloadableDriverLicenseFree",
  3638.                               "lblNPDownloadableDriverDescription",
  3639.                               "lblNPDownloadableDriverSupportContacts",
  3640.                               "hsDownloadableDriverPerfText",
  3641.                               "hsDownloadableDriverPerfLineArt",
  3642.                               "hsDownloadableDriverPerfGraphics",
  3643.                               "hsDownloadableDriverPerfPhoto",
  3644.                               "lblDownloadableDriverPerfTextUnknown",
  3645.                               "lblDownloadableDriverPerfLineArtUnknown",
  3646.                               "lblDownloadableDriverPerfGraphicsUnknown",
  3647.                               "lblDownloadableDriverPerfPhotoUnknown",
  3648.                               "frmNPDownloadableDriverLicenseTerms",
  3649.                               "tvNPDownloadableDriverLicense",
  3650.                               "rbtnNPDownloadLicenseYes",
  3651.                               "rbtnNPDownloadLicenseNo"],
  3652.                          "WaitWindow":
  3653.                              ["WaitWindow",
  3654.                               "lblWait"],
  3655.                          "SMBBrowseDialog":
  3656.                              ["SMBBrowseDialog",
  3657.                               "tvSMBBrowser",
  3658.                               "btnSMBBrowseOk"],
  3659.                          "InstallDialog":
  3660.                              ["InstallDialog",
  3661.                               "lblInstall"]})
  3662.  
  3663.         # Since some dialogs are reused we can't let the delete-event's
  3664.         # default handler destroy them
  3665.         for dialog in [self.SMBBrowseDialog]:
  3666.             dialog.connect ("delete-event", on_delete_just_hide)
  3667.  
  3668.         # share with mainapp
  3669.         self.busy = mainapp.busy
  3670.         self.ready = mainapp.ready
  3671.  
  3672.         gtk_label_autowrap.set_autowrap(self.NewPrinterWindow)
  3673.  
  3674.         self.ntbkNewPrinter.set_show_tabs(False)
  3675.         self.ntbkPPDSource.set_show_tabs(False)
  3676.         self.ntbkNPType.set_show_tabs(False)
  3677.         self.ntbkNPDownloadableDriverProperties.set_show_tabs(False)
  3678.  
  3679.         self.spinner = gtkspinner.Spinner (self.imgProcessWorking)
  3680.  
  3681.         # Set up OpenPrinting widgets.
  3682.         self.openprinting = cupshelpers.openprinting.OpenPrinting ()
  3683.         self.openprinting_query_handle = None
  3684.         combobox = self.cmbNPDownloadableDriverFoundPrinters
  3685.         cell = gtk.CellRendererText()
  3686.         combobox.pack_start (cell, True)
  3687.         combobox.add_attribute(cell, 'text', 0)
  3688.         if self.DOWNLOADABLE_ONLYPPD:
  3689.             for widget in [self.cbNPDownloadableDriverLicenseFree,
  3690.                            self.cbNPDownloadableDriverLicensePatents]:
  3691.                 widget.hide ()
  3692.  
  3693.         def protect_toggle (toggle_widget):
  3694.             active = toggle_widget.get_data ('protect_active')
  3695.             if active != None:
  3696.                 toggle_widget.set_active (active)
  3697.  
  3698.         for widget in [self.cbNPDownloadableDriverSupplierVendor,
  3699.                        self.cbNPDownloadableDriverLicenseFree,
  3700.                        self.cbNPDownloadableDriverLicensePatents]:
  3701.             widget.connect ('clicked', protect_toggle)
  3702.  
  3703.         for widget in [self.hsDownloadableDriverPerfText,
  3704.                        self.hsDownloadableDriverPerfLineArt,
  3705.                        self.hsDownloadableDriverPerfGraphics,
  3706.                        self.hsDownloadableDriverPerfPhoto]:
  3707.             widget.connect ('change-value',
  3708.                             lambda x, y, z: True)
  3709.  
  3710.         # Device list
  3711.         slct = self.tvNPDevices.get_selection ()
  3712.         slct.set_select_function (self.device_select_function)
  3713.         self.tvNPDevices.set_row_separator_func (self.device_row_separator_fn)
  3714.         self.tvNPDevices.connect ("row-activated", self.device_row_activated)
  3715.  
  3716.         # Devices expander
  3717.         self.expNPDeviceURIs.connect ("notify::expanded",
  3718.                                       self.on_expNPDeviceURIs_expanded)
  3719.  
  3720.         # SMB browser
  3721.         self.smb_store = gtk.TreeStore (gobject.TYPE_PYOBJECT)
  3722.         self.btnSMBBrowse.set_sensitive (PYSMB_AVAILABLE)
  3723.         if not PYSMB_AVAILABLE:
  3724.             self.btnSMBBrowse.set_tooltip_text (_("Browsing not available "
  3725.                                                   "(pysmbc not installed)"))
  3726.  
  3727.         self.tvSMBBrowser.set_model (self.smb_store)
  3728.  
  3729.         # SMB list columns
  3730.         col = gtk.TreeViewColumn (_("Share"))
  3731.         cell = gtk.CellRendererText ()
  3732.         col.pack_start (cell, False)
  3733.         col.set_cell_data_func (cell, self.smbbrowser_cell_share)
  3734.         self.tvSMBBrowser.append_column (col)
  3735.  
  3736.         col = gtk.TreeViewColumn (_("Comment"))
  3737.         cell = gtk.CellRendererText ()
  3738.         col.pack_start (cell, False)
  3739.         col.set_cell_data_func (cell, self.smbbrowser_cell_comment)
  3740.         self.tvSMBBrowser.append_column (col)
  3741.  
  3742.         slct = self.tvSMBBrowser.get_selection ()
  3743.         slct.set_select_function (self.smb_select_function)
  3744.  
  3745.         self.SMBBrowseDialog.set_transient_for(self.NewPrinterWindow)
  3746.  
  3747.         self.tvNPDrivers.set_has_tooltip(True)
  3748.         self.tvNPDrivers.connect("query-tooltip", self.on_NPDrivers_query_tooltip)
  3749.  
  3750.         ppd_filter = gtk.FileFilter()
  3751.         ppd_filter.set_name(_("PostScript Printer Description files (*.ppd, *.PPD, *.ppd.gz, *.PPD.gz, *.PPD.GZ)"))
  3752.         ppd_filter.add_pattern("*.ppd")
  3753.         ppd_filter.add_pattern("*.PPD")
  3754.         ppd_filter.add_pattern("*.ppd.gz")
  3755.         ppd_filter.add_pattern("*.PPD.gz")
  3756.         ppd_filter.add_pattern("*.PPD.GZ")
  3757.         self.filechooserPPD.add_filter(ppd_filter)
  3758.  
  3759.         ppd_filter = gtk.FileFilter()
  3760.         ppd_filter.set_name(_("All files (*)"))
  3761.         ppd_filter.add_pattern("*")
  3762.         self.filechooserPPD.add_filter(ppd_filter)
  3763.  
  3764.     def show_IPP_Error (self, exception, message):
  3765.         return show_IPP_Error (exception, message, parent=self.NewPrinterWindow)
  3766.  
  3767.     def option_changed(self, option):
  3768.         if option.is_changed():
  3769.             self.changed.add(option)
  3770.         else:
  3771.             self.changed.discard(option)
  3772.  
  3773.         if option.conflicts:
  3774.             self.conflicts.add(option)
  3775.         else:
  3776.             self.conflicts.discard(option)
  3777.         self.setDataButtonState()
  3778.  
  3779.         return
  3780.  
  3781.     def setDataButtonState(self):
  3782.         self.btnNPForward.set_sensitive(not bool(self.conflicts))
  3783.  
  3784.     def init(self, dialog_mode):
  3785.         self.dialog_mode = dialog_mode
  3786.         self.options = {} # keyword -> Option object
  3787.         self.changed = set()
  3788.         self.conflicts = set()
  3789.  
  3790.         combobox = self.cmbNPDownloadableDriverFoundPrinters
  3791.         combobox.set_model (gtk.ListStore (str, str))
  3792.         self.entNPDownloadableDriverSearch.set_text ('')
  3793.         button = self.btnNPDownloadableDriverSearch
  3794.         label = button.get_children ()[0].get_children ()[0].get_children ()[1]
  3795.         self.btnNPDownloadableDriverSearch_label = label
  3796.         label.set_text (_("Search"))
  3797.  
  3798.         if self.dialog_mode in ("printer", "printer_with_uri", "class"):
  3799.             if self.dialog_mode == "class":
  3800.                 name_proto = "class"
  3801.             else:
  3802.                 name_proto = "printer"
  3803.             self.entNPName.set_text (self.mainapp.makeNameUnique(name_proto))
  3804.             self.entNPName.grab_focus()
  3805.             for widget in [self.entNPLocation,
  3806.                            self.entNPDescription,
  3807.                            self.entSMBURI, self.entSMBUsername,
  3808.                            self.entSMBPassword]:
  3809.                 widget.set_text('')
  3810.  
  3811.         if self.dialog_mode == "printer_with_uri":
  3812.             device_dict = { }
  3813.             self.device = cupshelpers.Device (self.mainapp.device_uri,
  3814.                                               **device_dict)
  3815.  
  3816.         self.entNPTDirectJetPort.set_text('9100')
  3817.         self.rbtnSMBAuthPrompt.set_active(True)
  3818.  
  3819.         if self.dialog_mode == "printer":
  3820.             self.NewPrinterWindow.set_title(_("New Printer"))
  3821.             # Start on devices page (1, not 0)
  3822.             self.ntbkNewPrinter.set_current_page(1)
  3823.             self.fillDeviceTab()
  3824.             self.rbtnNPFoomatic.set_active (True)
  3825.             self.on_rbtnNPFoomatic_toggled(self.rbtnNPFoomatic)
  3826.             # Start fetching information from CUPS in the background
  3827.             self.new_printer_PPDs_loaded = False
  3828.             self.queryPPDs ()
  3829.  
  3830.         elif self.dialog_mode == "class":
  3831.             self.NewPrinterWindow.set_title(_("New Class"))
  3832.             self.fillNewClassMembers()
  3833.             # Start on name page
  3834.             self.ntbkNewPrinter.set_current_page(0)
  3835.         elif self.dialog_mode == "device":
  3836.             self.NewPrinterWindow.set_title(_("Change Device URI"))
  3837.             self.ntbkNewPrinter.set_current_page(1)
  3838.             self.fillDeviceTab(self.mainapp.printer.device_uri)
  3839.         elif self.dialog_mode == "ppd" or \
  3840.             self.dialog_mode == "printer_with_uri":
  3841.             if self.dialog_mode == "ppd":
  3842.                 self.NewPrinterWindow.set_title(_("Change Driver"))
  3843.             else:
  3844.                 self.NewPrinterWindow.set_title(_("New Printer"))
  3845.             self.ntbkNewPrinter.set_current_page(2)
  3846.             self.rbtnNPFoomatic.set_active (True)
  3847.             self.on_rbtnNPFoomatic_toggled(self.rbtnNPFoomatic)
  3848.             self.rbtnChangePPDKeepSettings.set_active(True)
  3849.  
  3850.             self.auto_model = ""
  3851.             ppd = self.mainapp.ppd
  3852.             #self.mainapp.devid = "MFG:Samsung;MDL:ML-3560;DES:;CMD:GDI;"
  3853.             devid = self.mainapp.devid
  3854.             if self.dialog_mode == "ppd":
  3855.                 uri = self.mainapp.printer.device_uri
  3856.             else:
  3857.                 uri = self.device.uri
  3858.                 if not self.install_hplip_plugin(uri):
  3859.                     self.on_NPCancel(None)
  3860.                     return
  3861.             if devid != "":
  3862.                 try:
  3863.                     devid_dict = cupshelpers.parseDeviceID (devid)
  3864.                     self.loadPPDs ()
  3865.                     reloaded = 0
  3866.                     while reloaded < 2:
  3867.                         (status, ppdname) = self.ppds.\
  3868.                             getPPDNameFromDeviceID (devid_dict["MFG"],
  3869.                                                     devid_dict["MDL"],
  3870.                                                     devid_dict["DES"],
  3871.                                                     devid_dict["CMD"],
  3872.                                                     uri,
  3873.                                                     self.jockey_installed_files)
  3874.                         if (status != self.ppds.STATUS_SUCCESS and
  3875.                             reloaded == 0):
  3876.                             try:
  3877.                                 if self.fetchJockeyDriver ():
  3878.                                     try:
  3879.                                         self.dropPPDs ()
  3880.                                         self.loadPPDs ()
  3881.                                         reloaded = 1
  3882.                                     except:
  3883.                                         reloaded = 2
  3884.                                 else:
  3885.                                     reloaded = 2
  3886.                             except:
  3887.                                 reloaded = 2
  3888.                         else:
  3889.                             reloaded = 2
  3890.                     if ppdname:
  3891.                         ppddict = self.ppds.getInfoFromPPDName (ppdname)
  3892.                         make_model = ppddict['ppd-make-and-model']
  3893.                         (self.auto_make, self.auto_model) = \
  3894.                             cupshelpers.ppds.ppdMakeModelSplit (make_model)
  3895.                         if (status == self.ppds.STATUS_SUCCESS and \
  3896.                             self.dialog_mode != "ppd"):
  3897.                             self.exactdrivermatch = True
  3898.                             self.fillMakeList()
  3899.                             self.ntbkNewPrinter.set_current_page(6)
  3900.                             self.nextNPTab(step = 0)
  3901.                         else:
  3902.                             self.exactdrivermatch = False
  3903.                     else:
  3904.                         self.auto_make = devid_dict["MFG"]
  3905.                         self.auto_model = devid_dict["MDL"]
  3906.                 except:
  3907.                     self.auto_make = devid_dict["MFG"]
  3908.                     self.auto_model = devid_dict["MDL"]
  3909.                 if not self.device or not self.device.id:
  3910.                     self.device.id = devid
  3911.                     self.device.id_dict = \
  3912.                         cupshelpers.parseDeviceID (self.device.id)
  3913.                 self.mainapp.devid = ""
  3914.             elif ppd:
  3915.                 attr = ppd.findAttr("Manufacturer")
  3916.                 if attr:
  3917.                     mfr = attr.value
  3918.                 else:
  3919.                     mfr = ""
  3920.                 makeandmodel = mfr
  3921.                 attr = ppd.findAttr("ModelName")
  3922.                 if not attr: attr = ppd.findAttr("ShortNickName")
  3923.                 if not attr: attr = ppd.findAttr("NickName")
  3924.                 if attr:
  3925.                     if attr.value.startswith(mfr):
  3926.                         makeandmodel = attr.value
  3927.                     else:
  3928.                         makeandmodel += ' ' + attr.value
  3929.                 else:
  3930.                     makeandmodel = ''
  3931.  
  3932.                 (self.auto_make,
  3933.                  self.auto_model) = \
  3934.                  cupshelpers.ppds.ppdMakeModelSplit (makeandmodel)
  3935.             else:
  3936.                 # Special CUPS names for a raw queue.
  3937.                 self.auto_make = 'Raw'
  3938.                 self.auto_model = 'Queue'
  3939.  
  3940.             try:
  3941.                 if self.dialog_mode == "ppd":
  3942.                     parent = self.mainapp.PrinterPropertiesDialog
  3943.                 else:
  3944.                     parent = self.NewPrinterWindow
  3945.  
  3946.                 self.loadPPDs (parent=parent)
  3947.             except cups.IPPError, (e, m):
  3948.                 show_IPP_Error (e, m, parent=self.mainapp.PrintersWindow)
  3949.                 return
  3950.             except:
  3951.                 return
  3952.  
  3953.             self.fillMakeList()
  3954.  
  3955.         self.setNPButtons()
  3956.         self.NewPrinterWindow.show()
  3957.  
  3958.     # Get a new driver with Jockey
  3959.  
  3960.     def queryJockeyDriver(self):
  3961.         debugprint ("queryJockeyDriver")
  3962.         if not self.jockey_lock.acquire(0):
  3963.             debugprint ("queryJockeyDriver: in progress")
  3964.             return
  3965.         debugprint ("Lock acquired for Jockey driver thread")
  3966.         # Start new thread
  3967.         devid = ""
  3968.         try:
  3969.             devid = self.device.id
  3970.         except:
  3971.             pass
  3972.         if devid == '':
  3973.             try:
  3974.                 devid = self.mainapp.devid
  3975.             except:
  3976.                 pass
  3977.         if devid == '':
  3978.             self.jockey_lock.release ()
  3979.             return
  3980.         thread.start_new_thread (self.getJockeyDriver_thread, (devid,))
  3981.         debugprint ("Jockey driver thread started")
  3982.  
  3983.     def getJockeyDriver_thread(self, id):
  3984.         debugprint ("Requesting driver from Jockey: %s" % id)
  3985.         self.jockey_driver_result = False
  3986.         self.jockey_installed_files = []
  3987.         try:
  3988.             bus = dbus.SessionBus()
  3989.             obj = bus.get_object("com.ubuntu.DeviceDriver", "/GUI")
  3990.             jockeyloader = \
  3991.                 dbus.Interface(obj, "com.ubuntu.DeviceDriver")
  3992.             (result, installedfiles) = \
  3993.                 jockeyloader.search_driver("printer_deviceid:%s" % id,
  3994.                                            timeout=999999)
  3995.             self.jockey_driver_result = result
  3996.             self.jockey_installed_files = installedfiles
  3997.             if result:
  3998.                 debugprint ("New driver downloaded and installed")
  3999.             else:
  4000.                 debugprint ("No new driver found or download rejected")
  4001.         except dbus.DBusException, e:
  4002.             self.jockey_driver_result = e
  4003.             debugprint (self.jockey_driver_result)
  4004.         except Exception, e:
  4005.             nonfatalException()
  4006.             self.jockey_driver_result = e
  4007.             debugprint ("Non-D-Bus error on Jockey call: %s" % e)
  4008.  
  4009.         debugprint ("Releasing Jockey driver lock")
  4010.         self.jockey_lock.release ()
  4011.  
  4012.     def fetchJockeyDriver(self, parent=None):
  4013.         debugprint ("fetchJockeyDriver")
  4014.         self.queryJockeyDriver()
  4015.         time.sleep (0.01)
  4016.  
  4017.         # Keep the UI refreshed while we wait for the driver to load.
  4018.         waiting = False
  4019.         while (self.jockey_lock.locked()):
  4020.             if not waiting:
  4021.                 waiting = True
  4022.                 self.lblWait.set_markup ('<span weight="bold" size="larger">' +
  4023.                                          _('Searching') + '</span>\n\n' +
  4024.                                          _('Searching for downloadable drivers'))
  4025.                 if not parent:
  4026.                     parent = self.NewPrinterWindow
  4027.                 self.WaitWindow.set_transient_for (parent)
  4028.                 self.WaitWindow.show ()
  4029.                 self.busy (self.WaitWindow)
  4030.  
  4031.             if self.mainapp.cups == None:
  4032.                 debugprint("CUPS connection lost, reconnecting ...")
  4033.                 try:
  4034.                     self.mainapp.cups = authconn.Connection(self.mainapp.PrintersWindow)
  4035.                     self.mainapp.setConnected()
  4036.                     debugprint("Reconnected")
  4037.                     self.mainapp.populateList()
  4038.                 except RuntimeError:
  4039.                     debugprint("Reconnection failed")
  4040.                     pass
  4041.  
  4042.             while gtk.events_pending ():
  4043.                 gtk.main_iteration ()
  4044.  
  4045.             time.sleep (0.1)
  4046.  
  4047.         if waiting:
  4048.             self.WaitWindow.hide ()
  4049.  
  4050.         debugprint ("Driver download request finished")
  4051.         result = self.jockey_driver_result # atomic operation
  4052.         if isinstance (result, Exception):
  4053.             # Propagate exception.
  4054.             raise result
  4055.         return result
  4056.  
  4057.     # get PPDs
  4058.  
  4059.     def queryPPDs(self):
  4060.         debugprint ("queryPPDs")
  4061.         if not self.ppds_lock.acquire(0):
  4062.             debugprint ("queryPPDs: in progress")
  4063.             return
  4064.         debugprint ("Lock acquired for PPDs thread")
  4065.         self.ppds_queried = True
  4066.         # Start new thread
  4067.         thread.start_new_thread (self.getPPDs_thread, (self.language[0],))
  4068.         debugprint ("PPDs thread started")
  4069.  
  4070.     def getPPDs_thread(self, language):
  4071.         try:
  4072.             debugprint ("Connecting (PPDs)")
  4073.             cups.setUser (self.mainapp.connect_user)
  4074.             cups.setPasswordCB (lambda x: '')
  4075.             c = cups.Connection (host=self.mainapp.connect_server,
  4076.                                  encryption=self.mainapp.connect_encrypt)
  4077.             debugprint ("Fetching PPDs")
  4078.             ppds_dict = c.getPPDs()
  4079.             self.ppds_result = cupshelpers.ppds.PPDs(ppds_dict,
  4080.                                                      language=language)
  4081.             debugprint ("Closing connection (PPDs)")
  4082.             del c
  4083.         except cups.IPPError, (e, msg):
  4084.             self.ppds_result = cups.IPPError (e, msg)
  4085.         except Exception, e:
  4086.             nonfatalException()
  4087.             self.ppds_result = e
  4088.  
  4089.         debugprint ("Releasing PPDs lock")
  4090.         self.ppds_lock.release ()
  4091.  
  4092.     def fetchPPDs(self, parent=None):
  4093.         debugprint ("fetchPPDs")
  4094.         if not self.ppds_queried:
  4095.             self.queryPPDs ()
  4096.  
  4097.         # Keep the UI refreshed while we wait for the devices to load.
  4098.         waiting = False
  4099.         while (self.ppds_lock.locked()):
  4100.             if not waiting:
  4101.                 waiting = True
  4102.                 self.lblWait.set_markup ('<span weight="bold" size="larger">' +
  4103.                                          _('Searching') + '</span>\n\n' +
  4104.                                          _('Searching for drivers'))
  4105.                 if not parent:
  4106.                     parent = self.NewPrinterWindow
  4107.                 self.WaitWindow.set_transient_for (parent)
  4108.                 self.WaitWindow.show ()
  4109.                 self.busy (self.WaitWindow)
  4110.  
  4111.             while gtk.events_pending ():
  4112.                 gtk.main_iteration ()
  4113.  
  4114.             time.sleep (0.1)
  4115.  
  4116.         if waiting:
  4117.             self.WaitWindow.hide ()
  4118.  
  4119.         debugprint ("Got PPDs")
  4120.         self.ppds_queried = False
  4121.         result = self.ppds_result # atomic operation
  4122.         if isinstance (result, Exception):
  4123.             # Propagate exception.
  4124.             raise result
  4125.         return result
  4126.  
  4127.     def loadPPDs(self, parent=None):
  4128.         try:
  4129.             return self.ppds
  4130.         except:
  4131.             self.ppds = self.fetchPPDs (parent=parent)
  4132.             return self.ppds
  4133.  
  4134.     def dropPPDs(self):
  4135.         try:
  4136.             del self.ppds
  4137.         except:
  4138.             pass
  4139.  
  4140.     # Class members
  4141.  
  4142.     def fillNewClassMembers(self):
  4143.         model = self.tvNCMembers.get_model()
  4144.         model.clear()
  4145.         model = self.tvNCNotMembers.get_model()
  4146.         model.clear()
  4147.         for printer in self.mainapp.printers.itervalues():
  4148.             model.append((printer.name,))
  4149.  
  4150.     def on_btnNCAddMember_clicked(self, button):
  4151.         moveClassMembers(self.tvNCNotMembers, self.tvNCMembers)
  4152.         self.btnNPApply.set_sensitive(
  4153.             bool(getCurrentClassMembers(self.tvNCMembers)))
  4154.         button.set_sensitive(False)
  4155.  
  4156.     def on_btnNCDelMember_clicked(self, button):
  4157.         moveClassMembers(self.tvNCMembers, self.tvNCNotMembers)
  4158.         self.btnNPApply.set_sensitive(
  4159.             bool(getCurrentClassMembers(self.tvNCMembers)))
  4160.         button.set_sensitive(False)
  4161.  
  4162.     def on_tvNCMembers_cursor_changed(self, widget):
  4163.         selection = widget.get_selection()
  4164.         model_from, rows = selection.get_selected_rows()
  4165.         self.btnNCDelMember.set_sensitive(rows != [])
  4166.  
  4167.     def on_tvNCNotMembers_cursor_changed(self, widget):
  4168.         selection = widget.get_selection()
  4169.         model_from, rows = selection.get_selected_rows()
  4170.         self.btnNCAddMember.set_sensitive(rows != [])
  4171.  
  4172.     # Navigation buttons
  4173.  
  4174.     def on_NPCancel(self, widget, event=None):
  4175.         self.NewPrinterWindow.hide()
  4176.         if self.openprinting_query_handle != None:
  4177.             self.openprinting.cancelOperation (self.openprinting_query_handle)
  4178.             self.openprinting_query_handle = None
  4179.         return True
  4180.  
  4181.     def on_btnNPBack_clicked(self, widget):
  4182.         self.nextNPTab(-1)
  4183.  
  4184.     def on_btnNPForward_clicked(self, widget):
  4185.         self.nextNPTab()
  4186.  
  4187.     def nextNPTab(self, step=1):
  4188.         page_nr = self.ntbkNewPrinter.get_current_page()
  4189.  
  4190.         if self.dialog_mode == "class":
  4191.             order = [0, 4, 5]
  4192.         elif self.dialog_mode == "printer" or \
  4193.                 self.dialog_mode == "printer_with_uri":
  4194.             self.busy (self.NewPrinterWindow)
  4195.             if page_nr == 1: # Device (first page)
  4196.                 self.auto_make, self.auto_model = None, None
  4197.                 self.device.uri = self.getDeviceURI()
  4198.                 if not self.install_hplip_plugin(self.device.uri):
  4199.                     self.on_NPCancel(None)
  4200.                     return
  4201.                 uri = self.device.uri
  4202.                 if uri and uri.startswith ("smb://"):
  4203.                     uri = SMBURI (uri=uri[6:]).sanitize_uri ()
  4204.  
  4205.                 # Try to access the PPD, in this case our detected IPP
  4206.                 # printer is a queue on a remote CUPS server which is
  4207.                 # not automatically set up on our local CUPS server
  4208.                 # (for example DNS-SD broadcasted queue from Mac OS X)
  4209.                 self.remotecupsqueue = None
  4210.                 res = re.search ("ipp://(\S+(:\d+|))/printers/(\S+)", uri)
  4211.                 if res:
  4212.                     resg = res.groups()
  4213.                     try:
  4214.                         conn = httplib.HTTPConnection(resg[0])
  4215.                         conn.request("GET", "/printers/%s.ppd" % resg[2])
  4216.                         resp = conn.getresponse()
  4217.                         if resp.status == 200: self.remotecupsqueue = resg[2]
  4218.                     except:
  4219.                         pass
  4220.  
  4221.                     # We also want to fetch the printer-info and
  4222.                     # printer-location attributes, to pre-fill those
  4223.                     # fields for this new queue.
  4224.                     try:
  4225.                         if len (resg[1]) > 0:
  4226.                             port = int (resg[1])
  4227.                         else:
  4228.                             port = 631
  4229.  
  4230.                         encryption = cups.HTTP_ENCRYPT_IF_REQUESTED
  4231.                         c = cups.Connection (host=resg[0],
  4232.                                              port=port,
  4233.                                              encryption=encryption)
  4234.  
  4235.                         r = ['printer-info', 'printer-location']
  4236.                         attrs = c.getPrinterAttributes (uri=uri,
  4237.                                                         requested_attributes=r)
  4238.                         info = attrs.get ('printer-info', '')
  4239.                         location = attrs.get ('printer-location', '')
  4240.                         if len (info) > 0:
  4241.                             self.entNPDescription.set_text (info)
  4242.                         if len (location) > 0:
  4243.                             self.entNPLocation.set_text (location)
  4244.                     except RuntimeError:
  4245.                         pass
  4246.                     except:
  4247.                         nonfatalException ()
  4248.                 else:
  4249.                     # Remote CUPS queue discovered by "dnssd" CUPS backend
  4250.                     res = re.search ("(dnssd|mdns)://([^\./]+)(\.[^/]+|)/cups",
  4251.                                      uri)
  4252.                     if res and self.device.id_dict and \
  4253.                        self.device.id_dict.get ('MDL', ''):
  4254.                         resg = res.groups()
  4255.                         self.remotecupsqueue = self.device.info
  4256.                     
  4257.                 if (not self.remotecupsqueue and
  4258.                     not self.new_printer_PPDs_loaded):
  4259.                     try:
  4260.                         self.loadPPDs(self.NewPrinterWindow)
  4261.                     except cups.IPPError, (e, msg):
  4262.                         self.ready (self.NewPrinterWindow)
  4263.                         self.show_IPP_Error(e, msg)
  4264.                         return
  4265.                     except:
  4266.                         self.ready (self.NewPrinterWindow)
  4267.                         return
  4268.                     self.new_printer_PPDs_loaded = True
  4269.  
  4270.                 ppdname = None
  4271.                 try:
  4272.                     if self.remotecupsqueue:
  4273.                         # We have a remote CUPS queue, let the client queue
  4274.                         # stay raw so that the driver on the server gets used
  4275.                         ppdname = 'raw'
  4276.                         self.ppd = ppdname
  4277.                         name = self.remotecupsqueue
  4278.                         name = self.mainapp.makeNameUnique (name)
  4279.                         self.entNPName.set_text (name)
  4280.                     elif self.device.id or \
  4281.                             (self.device.make_and_model and \
  4282.                              self.device.make_and_model != "Unknown"):
  4283.                         if self.device.id:
  4284.                             id_dict = self.device.id_dict
  4285.                         else:
  4286.                             id_dict = {}
  4287.                             (id_dict["MFG"], id_dict["MDL"]) = \
  4288.                                 cupshelpers.ppds.ppdMakeModelSplit \
  4289.                                     (self.device.make_and_model)
  4290.                             id_dict["DES"] = ""
  4291.                             id_dict["CMD"] = ()
  4292.                         reloaded = 0
  4293.                         while reloaded < 2:
  4294.                             (status, ppdname) = self.ppds.\
  4295.                                 getPPDNameFromDeviceID (id_dict["MFG"],
  4296.                                                         id_dict["MDL"],
  4297.                                                         id_dict["DES"],
  4298.                                                         id_dict["CMD"],
  4299.                                                         self.device.uri,
  4300.                                                         self.jockey_installed_files)
  4301.                             if (status != self.ppds.STATUS_SUCCESS and
  4302.                                 reloaded == 0):
  4303.                                 #if reloaded == 0:
  4304.                                 #self.device.id = "MFG:Samsung;MDL:ML-1610;DES:;CMD:GDI;"
  4305.                                 #id_dict = cupshelpers.parseDeviceID(self.device.id)
  4306.                                 try:
  4307.                                     if self.fetchJockeyDriver ():
  4308.                                         try:
  4309.                                             self.dropPPDs ()
  4310.                                             self.loadPPDs ()
  4311.                                             reloaded = 1
  4312.                                         except:
  4313.                                             reloaded = 2
  4314.                                     else:
  4315.                                         reloaded = 2
  4316.                                 except:
  4317.                                     reloaded = 2
  4318.                             else:
  4319.                                 reloaded = 2
  4320.                     else:
  4321.                         (status, ppdname) = self.ppds.\
  4322.                             getPPDNameFromDeviceID ("Generic",
  4323.                                                     "Printer",
  4324.                                                     "Generic Printer",
  4325.                                                     [],
  4326.                                                     self.device.uri)
  4327.  
  4328.                     if ppdname and not self.remotecupsqueue:
  4329.                         ppddict = self.ppds.getInfoFromPPDName (ppdname)
  4330.                         make_model = ppddict['ppd-make-and-model']
  4331.                         (make, model) = \
  4332.                             cupshelpers.ppds.ppdMakeModelSplit (make_model)
  4333.                         self.auto_make = make
  4334.                         self.auto_model = model
  4335.                         if (status == self.ppds.STATUS_SUCCESS and \
  4336.                             self.dialog_mode != "ppd"):
  4337.                             self.exactdrivermatch = True
  4338.                         else:
  4339.                             self.exactdrivermatch = False
  4340.                 except:
  4341.                     nonfatalException ()
  4342.  
  4343.                 if not self.remotecupsqueue:
  4344.                     self.fillMakeList()
  4345.             elif page_nr == 3: # Model has been selected
  4346.                 if not self.device.id:
  4347.                     # Choose an appropriate name when no Device ID
  4348.                     # is available, based on the model the user has
  4349.                     # selected.
  4350.                     try:
  4351.                         model, iter = self.tvNPModels.get_selection ().\
  4352.                                       get_selected ()
  4353.                         name = model.get(iter, 0)[0]
  4354.                         name = self.mainapp.makeNameUnique (name)
  4355.                         self.entNPName.set_text (name)
  4356.                     except:
  4357.                         nonfatalException ()
  4358.  
  4359.             self.ready (self.NewPrinterWindow)
  4360.             if self.dialog_mode == "printer":
  4361.                 if self.remotecupsqueue:
  4362.                     order = [1, 0]
  4363.                 elif self.exactdrivermatch:
  4364.                     order = [1, 6, 0]
  4365.                 elif self.rbtnNPFoomatic.get_active():
  4366.                     order = [1, 2, 3, 6, 0]
  4367.                 elif self.rbtnNPPPD.get_active():
  4368.                     order = [1, 2, 6, 0]
  4369.                 else:
  4370.                     # Downloadable driver
  4371.                     order = [1, 2, 7, 6, 0]
  4372.             else:
  4373.                 if self.remotecupsqueue:
  4374.                     order = [0]
  4375.                 elif self.exactdrivermatch:
  4376.                     order = [6, 0]
  4377.                 elif self.rbtnNPFoomatic.get_active():
  4378.                     order = [2, 3, 6, 0]
  4379.                 elif self.rbtnNPPPD.get_active():
  4380.                     order = [2, 6, 0]
  4381.                 else:
  4382.                     # Downloadable driver
  4383.                     order = [2, 7, 6, 0]
  4384.         elif self.dialog_mode == "device":
  4385.             order = [1]
  4386.         elif self.dialog_mode == "ppd":
  4387.             if self.rbtnNPFoomatic.get_active():
  4388.                 order = [2, 3, 5, 6]
  4389.             elif self.rbtnNPPPD.get_active():
  4390.                 order = [2, 5, 6]
  4391.             else:
  4392.                 # Downloadable driver
  4393.                 order = [2, 7, 5, 6]
  4394.  
  4395.         next_page_nr = order[order.index(page_nr)+step]
  4396.  
  4397.         # fill Installable Options tab
  4398.         fetch_ppd = False
  4399.         try:
  4400.             if order.index (5) > -1:
  4401.                 # There is a copy settings page in this set
  4402.                 fetch_ppd = next_page_nr == 5 and step >= 0
  4403.         except ValueError:
  4404.             fetch_ppd = next_page_nr == 6 and step >= 0
  4405.  
  4406.         debugprint ("Will fetch ppd? %d" % fetch_ppd)
  4407.         if fetch_ppd:
  4408.             self.ppd = self.getNPPPD()
  4409.             self.installable_options = False
  4410.             if self.ppd == None:
  4411.                 return
  4412.  
  4413.             # Prepare Installable Options screen.
  4414.             if isinstance(self.ppd, cups.PPD):
  4415.                 self.fillNPInstallableOptions()
  4416.             else:
  4417.                 # Put a label there explaining why the page is empty.
  4418.                 ppd = self.ppd
  4419.                 self.ppd = None
  4420.                 self.fillNPInstallableOptions()
  4421.                 self.ppd = ppd
  4422.  
  4423.             if not self.installable_options:
  4424.                 if next_page_nr == 6:
  4425.                     # step over if empty
  4426.                     next_page_nr = order[order.index(next_page_nr)+1]
  4427.  
  4428.         # Step over empty Installable Options tab when moving backwards.
  4429.         if next_page_nr == 6 and not self.installable_options and step<0:
  4430.             next_page_nr = order[order.index(next_page_nr)-1]
  4431.  
  4432.         if step >= 0 and next_page_nr == 7: # About to show downloadable drivers
  4433.             if self.drivers_lock.locked ():
  4434.                 # Still searching for drivers.
  4435.                 self.lblWait.set_markup ('<span weight="bold" size="larger">' +
  4436.                                          _('Searching') + '</span>\n\n' +
  4437.                                          _('Searching for drivers'))
  4438.                 self.WaitWindow.set_transient_for (self.NewPrinterWindow)
  4439.                 self.WaitWindow.show ()
  4440.                 self.busy (self.WaitWindow)
  4441.                 self.busy (self.NewPrinterWindow)
  4442.  
  4443.                 # Keep the UI refreshed while we wait for the drivers
  4444.                 # query to complete.
  4445.                 while self.drivers_lock.locked ():
  4446.                     while gtk.events_pending ():
  4447.                         gtk.main_iteration ()
  4448.                     time.sleep (0.1)
  4449.  
  4450.                 self.ready (self.NewPrinterWindow)
  4451.                 self.WaitWindow.hide ()
  4452.  
  4453.             self.fillDownloadableDrivers()
  4454.  
  4455.         if step >= 0 and next_page_nr == 0: # About to choose a name.
  4456.             # Suggest an appropriate name.
  4457.             name = None
  4458.             descr = None
  4459.  
  4460.             try:
  4461.                 if self.device.id and not self.device.type in \
  4462.                        ("socket", "lpd", "ipp", "http", "https", "bluetooth"):
  4463.                     name = "%s %s" % (self.device.id_dict["MFG"], self.device.id_dict["MDL"])
  4464.                     descr = "%s %s" % (self.device.id_dict["MFG"], self.device.id_dict["MDL"])
  4465.             except:
  4466.                 nonfatalException ()
  4467.  
  4468.             try:
  4469.                 if name == None and isinstance (self.ppd, cups.PPD):
  4470.                     mname = self.ppd.findAttr ("modelName").value
  4471.                     make, model = cupshelpers.ppds.ppdMakeModelSplit (mname)
  4472.                     name = "%s %s" % (make, model)
  4473.                     descr = "%s %s" % (make, model)
  4474.             except:
  4475.                 nonfatalException ()
  4476.  
  4477.             if name == None:
  4478.                 name = 'printer'
  4479.  
  4480.             name = self.mainapp.makeNameUnique (name)
  4481.             self.entNPName.set_text (name)
  4482.  
  4483.             if self.entNPDescription.get_text () == '' and descr:
  4484.                 self.entNPDescription.set_text (descr)
  4485.  
  4486.         self.ntbkNewPrinter.set_current_page(next_page_nr)
  4487.  
  4488.         self.setNPButtons()
  4489.  
  4490.     def setNPButtons(self):
  4491.         nr = self.ntbkNewPrinter.get_current_page()
  4492.  
  4493.         if self.dialog_mode == "device":
  4494.             self.btnNPBack.hide()
  4495.             self.btnNPForward.hide()
  4496.             self.btnNPApply.show()
  4497.             try:
  4498.                 uri = self.getDeviceURI ()
  4499.                 valid = validDeviceURI (uri)
  4500.             except AttributeError:
  4501.                 # No device selected yet.
  4502.                 valid = False
  4503.             self.btnNPApply.set_sensitive (valid)
  4504.             return
  4505.  
  4506.         if self.dialog_mode == "ppd":
  4507.             if nr == 5: # Apply
  4508.                 if not self.installable_options:
  4509.                     # There are no installable options, so this is the
  4510.                     # last page.
  4511.                     debugprint ("No installable options")
  4512.                     self.btnNPForward.hide ()
  4513.                     self.btnNPApply.show ()
  4514.                 else:
  4515.                     self.btnNPForward.show ()
  4516.                     self.btnNPApply.hide ()
  4517.                 return
  4518.             elif nr == 6:
  4519.                 self.btnNPForward.hide()
  4520.                 self.btnNPApply.show()
  4521.                 return
  4522.             else:
  4523.                 self.btnNPForward.show()
  4524.                 self.btnNPApply.hide()
  4525.             if nr == 2:
  4526.                 self.btnNPBack.hide()
  4527.                 self.btnNPForward.show()
  4528.                 downloadable_selected = False
  4529.                 if self.rbtnNPDownloadableDriverSearch.get_active ():
  4530.                     combobox = self.cmbNPDownloadableDriverFoundPrinters
  4531.                     iter = combobox.get_active_iter ()
  4532.                     if iter and combobox.get_model ().get_value (iter, 1):
  4533.                         downloadable_selected = True
  4534.  
  4535.                 self.btnNPForward.set_sensitive(bool(
  4536.                         self.rbtnNPFoomatic.get_active() or
  4537.                         self.filechooserPPD.get_filename() or
  4538.                         downloadable_selected))
  4539.                 return
  4540.             else:
  4541.                 self.btnNPBack.show()
  4542.  
  4543.         # class/printer
  4544.  
  4545.         if nr == 1: # Device
  4546.             valid = False
  4547.             try:
  4548.                 uri = self.getDeviceURI ()
  4549.                 valid = validDeviceURI (uri)
  4550.             except:
  4551.                 pass
  4552.             self.btnNPForward.set_sensitive(valid)
  4553.             self.btnNPBack.hide ()
  4554.         else:
  4555.             self.btnNPBack.show()
  4556.  
  4557.         self.btnNPForward.show()
  4558.         self.btnNPApply.hide()
  4559.  
  4560.         if nr == 0: # Name
  4561.             self.btnNPBack.show()
  4562.             if self.dialog_mode == "printer" or \
  4563.                     self.dialog_mode == "printer_with_uri":
  4564.                 self.btnNPForward.hide()
  4565.                 self.btnNPApply.show()
  4566.                 self.btnNPApply.set_sensitive(
  4567.                     self.mainapp.checkNPName(self.entNPName.get_text()))
  4568.             if self.dialog_mode == "class":
  4569.                 # This is the first page for the New Class dialog, so
  4570.                 # hide the Back button.
  4571.                 self.btnNPBack.hide ()
  4572.             if self.dialog_mode == "printer_with_uri" and \
  4573.                     (self.remotecupsqueue or \
  4574.                          (self.exactdrivermatch and \
  4575.                               not self.installable_options)):
  4576.                 self.btnNPBack.hide ()
  4577.         if nr == 2: # Make/PPD file
  4578.             downloadable_selected = False
  4579.             if self.rbtnNPDownloadableDriverSearch.get_active ():
  4580.                 combobox = self.cmbNPDownloadableDriverFoundPrinters
  4581.                 iter = combobox.get_active_iter ()
  4582.                 if iter and combobox.get_model ().get_value (iter, 1):
  4583.                     downloadable_selected = True
  4584.  
  4585.             self.btnNPForward.set_sensitive(bool(
  4586.                 self.rbtnNPFoomatic.get_active() or
  4587.                 self.filechooserPPD.get_filename() or
  4588.                 downloadable_selected))
  4589.             # If we have an auto-detected printer for which there was no
  4590.             # driver found, we have already the URI and so this step is
  4591.             # not needed in the wizard. This makes manufacturer?PPD selection
  4592.             # the firts step
  4593.             if self.dialog_mode == "printer_with_uri":
  4594.                 self.btnNPBack.hide()
  4595.         if nr == 3: # Model/Driver
  4596.             model, iter = self.tvNPDrivers.get_selection().get_selected()
  4597.             self.btnNPForward.set_sensitive(bool(iter))
  4598.         if nr == 4: # Class Members
  4599.             self.btnNPForward.hide()
  4600.             self.btnNPApply.show()
  4601.             self.btnNPApply.set_sensitive(
  4602.                 bool(getCurrentClassMembers(self.tvNCMembers)))
  4603.         if nr == 6: # Installable options
  4604.             if self.dialog_mode == "printer_with_uri" and \
  4605.                     self.exactdrivermatch:
  4606.                 self.btnNPBack.hide ()
  4607.         if nr == 7: # Downloadable drivers
  4608.             if self.ntbkNPDownloadableDriverProperties.get_current_page() == 1:
  4609.                 accepted = self.rbtnNPDownloadLicenseYes.get_active ()
  4610.             else:
  4611.                 treeview = self.tvNPDownloadableDrivers
  4612.                 model, iter = treeview.get_selection ().get_selected ()
  4613.                 accepted = (iter != None)
  4614.  
  4615.             self.btnNPForward.set_sensitive(accepted)
  4616.  
  4617.     def on_entNPName_changed(self, widget):
  4618.         # restrict
  4619.         text = unicode (widget.get_text())
  4620.         new_text = text
  4621.         new_text = new_text.replace("/", "")
  4622.         new_text = new_text.replace("#", "")
  4623.         new_text = new_text.replace(" ", "")
  4624.         if text!=new_text:
  4625.             widget.set_text(new_text)
  4626.         if self.dialog_mode == "printer":
  4627.             self.btnNPApply.set_sensitive(
  4628.                 self.mainapp.checkNPName(new_text))
  4629.         else:
  4630.             self.btnNPForward.set_sensitive(
  4631.                 self.mainapp.checkNPName(new_text))
  4632.  
  4633.     def fetchDevices(self, parent=None):
  4634.         debugprint ("fetchDevices")
  4635.         self.lblWait.set_markup ('<span weight="bold" size="larger">' +
  4636.                                  _('Searching') + '</span>\n\n' +
  4637.                                  _('Searching for printers'))
  4638.         if parent == None:
  4639.             parent = self.mainapp.PrintersWindow
  4640.         self.WaitWindow.set_transient_for (parent)
  4641.         self.WaitWindow.show_now ()
  4642.         self.busy (self.WaitWindow)
  4643.         while gtk.events_pending ():
  4644.             gtk.main_iteration ()
  4645.  
  4646.         debugprint ("Fetching devices")
  4647.         self.mainapp.cups._begin_operation (_("fetching device list"))
  4648.         try:
  4649.             devices = cupshelpers.getDevices(self.mainapp.cups)
  4650.         except:
  4651.             self.mainapp.cups._end_operation ()
  4652.             self.WaitWindow.hide ()
  4653.             raise
  4654.  
  4655.         self.mainapp.cups._end_operation ()
  4656.         self.WaitWindow.hide ()
  4657.         debugprint ("Got devices")
  4658.         return devices
  4659.  
  4660.     def install_hplip_plugin(self, uri):
  4661.         """
  4662.         Attempt to install a plugin using hp-plugin.
  4663.  
  4664.         @return: True if plugin not needed (or needed and installed),
  4665.         False on error.
  4666.         """
  4667.  
  4668.         if not self.HP_PLUGIN_SUPPORT:
  4669.             return True
  4670.  
  4671.         # Check necessity of the plugin
  4672.         os.environ["URI"] = uri
  4673.         cmd = 'LC_ALL=C DISPLAY= hp-info -x -i -d"${URI}"'
  4674.         debugprint (uri + ": " + cmd)
  4675.         try:
  4676.             p = subprocess.Popen (cmd, shell=True,
  4677.                                   stdin=file("/dev/null"),
  4678.                                   stdout=subprocess.PIPE,
  4679.                                   stderr=subprocess.PIPE)
  4680.             (stdout, stderr) = p.communicate ()
  4681.             if p.returncode != 0:
  4682.                 return True # assume plugin not required
  4683.         except:
  4684.             # Problem executing command.
  4685.             return True # assume plugin not required
  4686.  
  4687.         plugin_needed = -1
  4688.         plugin_reason = -1
  4689.         fw_download = -1
  4690.         hpmodel = None
  4691.         hplip_version = None
  4692.         for line in stdout.split ("\n"):
  4693.             if line.find ("plugin ") >= 0:
  4694.                 res = re.search ("(\d+)", line)
  4695.                 if res:
  4696.                     resg = res.groups()
  4697.                     plugin_needed = int(resg[0])
  4698.             elif line.find ("plugin-reason") >= 0:
  4699.                 res = re.search ("(\d+)", line)
  4700.                 if res:
  4701.                     resg = res.groups()
  4702.                     plugin_reason = int(resg[0])
  4703.             elif line.find ("fw-download") >= 0:
  4704.                 if line.find ("True") >= 0:
  4705.                     fw_download = 1
  4706.                 elif line.find ("False") >= 0:
  4707.                     fw_download = 0
  4708.             elif line.find ("model") >= 0:
  4709.                 res = re.search ("^\s*model\s*(\S+)\s*$", line)
  4710.                 if res:
  4711.                     resg = res.groups()
  4712.                     hpmodel = resg[0]
  4713.             elif line.find ("HP Linux Imaging and Printing") >= 0:
  4714.                 res = re.search ("(\d+\.\d+\.\d+\w*)", line)
  4715.                 if res:
  4716.                     resg = res.groups()
  4717.                     hplip_version = resg[0]
  4718.             if plugin_needed >= 0 and plugin_reason >= 0 and \
  4719.                     fw_download >= 0 and hpmodel != None:
  4720.                 break
  4721.         if plugin_needed <= 0 or not hplip_version or not hpmodel:
  4722.             return True # assume plugin not required
  4723.         # Check whether the plugin is already installed
  4724.         if hplip_version.startswith("3"):
  4725.             os.environ["hp_model"] = hpmodel
  4726.             cmd = 'LC_ALL=C hp-mkuri -c'
  4727.             debugprint (uri + ": " + hpmodel)
  4728.             try:
  4729.                 p = subprocess.Popen (cmd, shell=True,
  4730.                                       stdin=file("/dev/null"),
  4731.                                       stdout=subprocess.PIPE,
  4732.                                       stderr=subprocess.PIPE)
  4733.                 (stdout, stderr) = p.communicate ()
  4734.                 if p.returncode < 2:
  4735.                     return True # plugin installed or not required
  4736.             except:
  4737.                 # Problem executing command.
  4738.                 return True # assume plugin not required
  4739.         else:
  4740.             if glob.glob("/usr/share/hplip/data/plugin/*%s*plugin*" %
  4741.                          hplip_version):
  4742.                 if hplip_version.startswith("2"):
  4743.                     try:
  4744.                         f = open('/etc/hp/hplip.conf', 'r')
  4745.                         for line in f:
  4746.                             if line.strip ().startswith("plugin") and \
  4747.                                     line.strip ().endswith("1"):
  4748.                                 f.close()
  4749.                                 return True
  4750.                             f.close()
  4751.                     except:
  4752.                         pass
  4753.                     else:
  4754.                         return True
  4755.  
  4756.         # Tell the user why he needs the plugin
  4757.         text = \
  4758.             _("For this printer a proprietary driver plugin from HP is available.\n")
  4759.         if plugin_needed == 1:
  4760.             text += \
  4761.                 _("The installation of the plugin is required for your printer to work.\n\n")
  4762.         elif plugin_needed == 2:
  4763.             text += \
  4764.                 _("Installing the plugin is optional, it completes or enhances the functionality\n"
  4765.                   "of your printer. Without plugin at least basic operations work.\n\n")
  4766.         if plugin_reason > 0:
  4767.             text += \
  4768.                 _("The plugin provides the following features:\n")
  4769.             if (plugin_reason & 0x1) != 0:
  4770.                 text += \
  4771.                     _(" - Printing support\n")
  4772.             if (plugin_reason & 0x2) != 0:
  4773.                 text += \
  4774.                     _(" - Faster printing\n")
  4775.             if (plugin_reason & 0x4) != 0:
  4776.                 text += \
  4777.                     _(" - Better printout quality\n")
  4778.             if (plugin_reason & 0x8) != 0:
  4779.                 text += \
  4780.                     _(" - Extra printing features\n")
  4781.             if (plugin_reason & 0x40) != 0:
  4782.                 text += \
  4783.                     _(" - Scanning support\n")
  4784.             if (plugin_reason & 0x80) != 0:
  4785.                 text += \
  4786.                     _(" - Faster scanning\n")
  4787.             if (plugin_reason & 0x100) != 0:
  4788.                 text += \
  4789.                     _(" - Better scanning image quality\n")
  4790.             if (plugin_reason & 0x800) != 0:
  4791.                 text += \
  4792.                     _(" - Faxing support\n")
  4793.             if (plugin_reason & 0x1000) != 0:
  4794.                 text += \
  4795.                     _(" - Extra fax features\n")
  4796.             if (plugin_reason & 0x4000) != 0:
  4797.                 text += \
  4798.                     _(" - Better Input/Output support\n")
  4799.             if (plugin_reason & 0x8000) != 0:
  4800.                 text += \
  4801.                     _(" - Extra user interface features\n")
  4802.             if (plugin_reason & 0x10000) != 0:
  4803.                 text += \
  4804.                     _(" - Other extra features\n")
  4805.             text += "\n"
  4806.         text += "Do you want to download and install the plugin now?\n"
  4807.         if plugin_needed == 1:
  4808.             text += "\nNOTE: The plugin is required for your printer. If you do not install it, your\nprinter will not work."
  4809.             buttons = (_("Install plugin"), 1, 
  4810.                        _("Do not set up printer"), 2,
  4811.                        _("Set up without plugin"), 3)
  4812.         else:
  4813.             buttons = (_("Yes"), 1,
  4814.                        _("No"), 3)
  4815.             
  4816.         dialog = gtk.Dialog(self.device.info,
  4817.                             self.NewPrinterWindow,
  4818.                             gtk.DIALOG_MODAL |
  4819.                             gtk.DIALOG_DESTROY_WITH_PARENT,
  4820.                             buttons)
  4821.         label = gtk.Label(text)
  4822.         dialog.vbox.pack_start(label, True, True, 0)
  4823.         label.show()
  4824.         button_clicked = dialog.run()
  4825.         dialog.destroy()
  4826.         if (button_clicked == 1):
  4827.             cmds = ("if python -c 'import PyQt4.QtGui' 2>/dev/null; then gksu -- hp-plugin -u; else exit 255; fi",
  4828.                     "gksu -- xterm -T 'HPLIP Plugin Installation' -sb -rightbar -e hp-plugin -i")
  4829.             try:
  4830.                 install_result = -1
  4831.                 for cmd in cmds:
  4832.                     p = subprocess.Popen(cmd, shell=True,
  4833.                                          stdin=file("/dev/null"),
  4834.                                          stdout=subprocess.PIPE,
  4835.                                          stderr=subprocess.PIPE)
  4836.                     (stdout, stderr) = p.communicate ()
  4837.                     install_result = p.returncode
  4838.                     if install_result != 255:
  4839.                         break
  4840.                 if install_result == 0:
  4841.                     return True
  4842.                 else:
  4843.                     return False
  4844.             except OSError, e:
  4845.                 debugprint ("Execution of hp-plugin failed: %s" % e)
  4846.                 return False
  4847.         elif (button_clicked == 2):
  4848.             return False
  4849.         elif (button_clicked == 3):
  4850.             return True
  4851.         return False
  4852.  
  4853.     def get_hpfax_device_id(self, faxuri):
  4854.         os.environ["URI"] = faxuri
  4855.         cmd = 'LC_ALL=C DISPLAY= hp-info -x -i -d"${URI}"'
  4856.         debugprint (faxuri + ": " + cmd)
  4857.         try:
  4858.             p = subprocess.Popen (cmd, shell=True,
  4859.                                   stdin=file("/dev/null"),
  4860.                                   stdout=subprocess.PIPE,
  4861.                                   stderr=subprocess.PIPE)
  4862.             (stdout, stderr) = p.communicate ()
  4863.         except:
  4864.             # Problem executing command.
  4865.             return None
  4866.  
  4867.         faxtype = -1
  4868.         for line in stdout.split ("\n"):
  4869.             if line.find ("fax-type") == -1:
  4870.                 continue
  4871.             res = re.search ("(\d+)", line)
  4872.             if res:
  4873.                 resg = res.groups()
  4874.                 faxtype = resg[0]
  4875.             if faxtype >= 0:
  4876.                 break
  4877.         if faxtype <= 0:
  4878.             return None
  4879.         elif faxtype == 4:
  4880.             return 'MFG:HP;MDL:Fax 2;DES:HP Fax 2;'
  4881.         else:
  4882.             return 'MFG:HP;MDL:Fax;DES:HP Fax;'
  4883.  
  4884.     def get_hplip_uri_for_network_printer(self, host, mode):
  4885.         os.environ["HOST"] = host
  4886.         if mode == "print": mod = "-c"
  4887.         elif mode == "fax": mod = "-f"
  4888.         else: mod = "-c"
  4889.         cmd = 'hp-makeuri ' + mod + ' "${HOST}"'
  4890.         debugprint (host + ": " + cmd)
  4891.         uri = None
  4892.         try:
  4893.             p = subprocess.Popen (cmd, shell=True,
  4894.                                   stdin=file("/dev/null"),
  4895.                                   stdout=subprocess.PIPE,
  4896.                                   stderr=subprocess.PIPE)
  4897.             (stdout, stderr) = p.communicate ()
  4898.             if p.returncode != 0:
  4899.                 return None
  4900.         except:
  4901.             # Problem executing command.
  4902.             return None
  4903.  
  4904.         uri = stdout.strip ()
  4905.         return uri
  4906.  
  4907.     def getNetworkPrinterMakeModel(self, host=None, device=None):
  4908.         """
  4909.         Try to determine the make and model for the currently selected
  4910.         network printer, and store this in the data structure for the
  4911.         printer.
  4912.         Returns (hostname or None, uri or None).
  4913.         """
  4914.         uri = None
  4915.         if device == None:
  4916.             device = self.device
  4917.         # Determine host name/IP
  4918.         if host == None:
  4919.             s = device.uri.find ("://")
  4920.             if s != -1:
  4921.                 s += 3
  4922.                 e = device.uri[s:].find (":")
  4923.                 if e == -1: e = device.uri[s:].find ("/")
  4924.                 if e == -1: e = device.uri[s:].find ("?")
  4925.                 if e == -1: e = len (device.uri)
  4926.                 host = device.uri[s:s+e]
  4927.         # Try to get make and model via SNMP
  4928.         if host:
  4929.             os.environ["HOST"] = host
  4930.             cmd = '/usr/lib/cups/backend/snmp "${HOST}"'
  4931.             debugprint (host + ": " + cmd)
  4932.             stdout = None
  4933.             try:
  4934.                 p = subprocess.Popen (cmd, shell=True,
  4935.                                       stdin=file("/dev/null"),
  4936.                                       stdout=subprocess.PIPE,
  4937.                                       stderr=subprocess.PIPE)
  4938.                 (stdout, stderr) = p.communicate ()
  4939.                 if p.returncode != 0:
  4940.                     stdout = None
  4941.             except:
  4942.                 # Problem executing command.
  4943.                 pass
  4944.  
  4945.             if stdout != None:
  4946.                 uri = re.sub("^\s*\S+\s+", "", stdout)
  4947.                 uri = re.sub("\s.*$", "", uri)
  4948.                 mm = re.sub("^\s*\S+\s+\S+\s+\"", "", stdout)
  4949.                 mm = re.sub("\"\s+.*$", "", mm)
  4950.                 if mm and mm != "": device.make_and_model = mm
  4951.         # Extract make and model and create a pseudo device ID, so
  4952.         # that a PPD/driver can be assigned to the device
  4953.         make_and_model = None
  4954.         if len (device.make_and_model) > 7:
  4955.             make_and_model = device.make_and_model
  4956.         elif len (device.info) > 7:
  4957.             make_and_model = device.info
  4958.             make_and_model = re.sub("\s*(\(|\d+\.\d+\.\d+\.\d+).*$", "", make_and_model)
  4959.         if make_and_model and not device.id:
  4960.             mk = None
  4961.             md = None
  4962.             (mk, md) = cupshelpers.ppds.ppdMakeModelSplit (make_and_model)
  4963.             device.id = "MFG:" + mk + ";MDL:" + md + ";DES:" + mk + " " + md + ";"
  4964.             device.id_dict = cupshelpers.parseDeviceID (device.id)
  4965.             device.make_and_model = "%s %s" % (mk, md)
  4966.             device.info = device.make_and_model
  4967.  
  4968.         return (host, uri)
  4969.  
  4970.     def fillDeviceTab(self, current_uri=None):
  4971.         try:
  4972.             devices = self.fetchDevices()
  4973.         except cups.IPPError, (e, msg):
  4974.             self.show_IPP_Error(e, msg)
  4975.             devices = {}
  4976.         except:
  4977.             nonfatalException()
  4978.             devices = {}
  4979.  
  4980.         if current_uri:
  4981.             if devices.has_key (current_uri):
  4982.                 current = devices.pop(current_uri)
  4983.                 current.info += _(" (Current)")
  4984.             elif devices.has_key (current_uri.replace (":9100", "")):
  4985.                 current_uri = current_uri.replace (":9100", "")
  4986.                 current = devices.pop(current_uri)
  4987.                 current.info += _(" (Current)")
  4988.             else:
  4989.                 current = cupshelpers.Device (current_uri)
  4990.                 current.info = "Current device"
  4991.  
  4992.         devices = devices.values()
  4993.  
  4994.         for device in devices:
  4995.             if device.type == "socket":
  4996.                 # Remove default port to more easily find duplicate URIs
  4997.                 device.uri = device.uri.replace (":9100", "")
  4998.  
  4999.         # Map generic URIs to something canonical
  5000.         def replace_generic (device):
  5001.             if device.uri == "hp:/no_device_found":
  5002.                 device.uri = "hp"
  5003.             elif device.uri == "hpfax:/no_device_found":
  5004.                 device.uri = "hpfax"
  5005.             return device
  5006.  
  5007.         devices = map (replace_generic, devices)
  5008.  
  5009.         # Mark duplicate URIs for deletion
  5010.         for i in range (len (devices) - 1):
  5011.             for j in range (i + 1, len (devices)):
  5012.                 device1 = devices[i]
  5013.                 device2 = devices[j]
  5014.                 if device1.uri == "delete" or device2.uri == "delete":
  5015.                     continue
  5016.                 if device1.uri == device2.uri:
  5017.                     # Keep the one with the longer (better) device ID
  5018.                     if (not device1.id):
  5019.                         device1.uri = "delete"
  5020.                     elif (not device2.id):
  5021.                         device2.uri = "delete"
  5022.                     elif (len (device1.id) < len (device2.id)):
  5023.                         device1.uri = "delete"
  5024.                     else:
  5025.                         device2.uri = "delete"
  5026.         devices = filter(lambda x: x.uri not in ("hp", "hpfax",
  5027.                                                  "hal", "beh",
  5028.                                                  "scsi", "http", "delete"),
  5029.                          devices)
  5030.         self.devices = []
  5031.         for device in devices:
  5032.             physicaldevice = PhysicalDevice (device)
  5033.             try:
  5034.                 i = self.devices.index (physicaldevice)
  5035.                 self.devices[i].add_device (device)
  5036.             except ValueError:
  5037.                 self.devices.append (physicaldevice)
  5038.  
  5039.         self.devices.sort()
  5040.         other = cupshelpers.Device('', **{'device-info' :_("Other")})
  5041.         self.devices.append (PhysicalDevice (other))
  5042.         device_select_index = 0
  5043.         if current_uri:
  5044.             current_device = PhysicalDevice (current)
  5045.             try:
  5046.                 i = self.devices.index (current_device)
  5047.                 self.devices[i].add_device (current)
  5048.                 device_select_index = i
  5049.                 devs = self.devices[i].get_devices ()
  5050.             except ValueError:
  5051.                 self.devices.insert(0, current_device)
  5052.  
  5053.         model = gtk.TreeStore (gobject.TYPE_STRING,   # device-info
  5054.                                gobject.TYPE_PYOBJECT, # PhysicalDevice obj
  5055.                                gobject.TYPE_BOOLEAN)  # Separator?
  5056.         network_iter = model.append (None, row=[_("Network Printer"),
  5057.                                                 None,
  5058.                                                 False])
  5059.         network_dict = { 'device-class': 'network',
  5060.                          'device-info': _("Find Network Printer") }
  5061.         network = cupshelpers.Device ('network', **network_dict)
  5062.         find_nw_iter = model.append (network_iter,
  5063.                                      row=[network_dict['device-info'],
  5064.                                           PhysicalDevice (network), False])
  5065.         model.insert_after (network_iter, find_nw_iter, row=['', None, True])
  5066.         self.devices_find_nw_iter = find_nw_iter
  5067.         self.tvNPDevices.set_model (model)
  5068.  
  5069.         i = 0
  5070.         device_select_path = None
  5071.         for device in self.devices:
  5072.             devs = device.get_devices ()
  5073.             network = devs[0].device_class == 'network'
  5074.             row=[device.get_info (), device, False]
  5075.             if network:
  5076.                 if devs[0].uri != devs[0].type:
  5077.                     # An actual network printer device.  Put this at the top.
  5078.                     iter = model.insert_before (network_iter, find_nw_iter,
  5079.                                                 row=row)
  5080.  
  5081.                     # If this is the currently selected device we need
  5082.                     # to expand the "Network Printer" row so that it
  5083.                     # is visible.
  5084.                     if device_select_index == i:
  5085.                         network_path = model.get_path (network_iter)
  5086.                         self.tvNPDevices.expand_row (network_path, False)
  5087.                 else:
  5088.                     # Just a method of finding one.
  5089.                     iter = model.append (network_iter, row=row)
  5090.             else:
  5091.                 iter = model.insert_before(None, network_iter, row=row)
  5092.  
  5093.             if device_select_index == i:
  5094.                 device_select_path = model.get_path (iter)
  5095.                 self.tvNPDevices.scroll_to_cell (device_select_path,
  5096.                                                  row_align=0.5)
  5097.                 column = self.tvNPDevices.get_column (0)
  5098.                 self.tvNPDevices.set_cursor (device_select_path, column)
  5099.  
  5100.             i += 1
  5101.  
  5102.         connection_select_path = 0
  5103.         if current_uri:
  5104.             model = self.tvNPDeviceURIs.get_model ()
  5105.             iter = model.get_iter_first ()
  5106.             i = 0
  5107.             while iter:
  5108.                 dev = model.get_value (iter, 1)
  5109.                 if current_uri == dev.uri:
  5110.                     connection_select_path = i
  5111.                     break
  5112.  
  5113.                 iter = model.iter_next (iter)
  5114.                 i += 1
  5115.  
  5116.         column = self.tvNPDeviceURIs.get_column (0)
  5117.         self.tvNPDeviceURIs.set_cursor (connection_select_path, column)
  5118.  
  5119.     def on_entNPTDevice_changed(self, entry):
  5120.         self.setNPButtons()
  5121.  
  5122.     ## SMB browsing
  5123.  
  5124.     def browse_smb_hosts(self):
  5125.         """Initialise the SMB tree store."""
  5126.         store = self.smb_store
  5127.         store.clear ()
  5128.         self.busy(self.SMBBrowseDialog)
  5129.         class X:
  5130.             pass
  5131.         dummy = X()
  5132.         dummy.smbc_type = pysmb.smbc.PRINTER_SHARE
  5133.         dummy.name = _('Scanning...')
  5134.         dummy.comment = ''
  5135.         store.append(None, [dummy])
  5136.         while gtk.events_pending ():
  5137.             gtk.main_iteration ()
  5138.  
  5139.         debug = 0
  5140.         if get_debugging ():
  5141.             debug = 10
  5142.         smbc_auth = pysmb.AuthContext (self.SMBBrowseDialog)
  5143.         ctx = pysmb.smbc.Context (debug=debug,
  5144.                                   auth_fn=smbc_auth.callback)
  5145.         entries = None
  5146.         try:
  5147.             while smbc_auth.perform_authentication () > 0:
  5148.                 try:
  5149.                     entries = ctx.opendir ("smb://").getdents ()
  5150.                 except Exception, e:
  5151.                     smbc_auth.failed (e)
  5152.         except RuntimeError, (e, s):
  5153.             if e != errno.ENOENT:
  5154.                 debugprint ("Runtime error: %s" % repr ((e, s)))
  5155.         except:
  5156.             nonfatalException ()
  5157.  
  5158.         store.clear ()
  5159.         if entries:
  5160.             for entry in entries:
  5161.                 if entry.smbc_type in [pysmb.smbc.WORKGROUP,
  5162.                                        pysmb.smbc.SERVER]:
  5163.                     iter = store.append (None, [entry])
  5164.                     i = store.append (iter)
  5165.  
  5166.         specified_uri = SMBURI (uri=self.entSMBURI.get_text ())
  5167.         (group, host, share, user, password) = specified_uri.separate ()
  5168.         if len (host) > 0:
  5169.             # The user has specified a server before clicking Browse.
  5170.             # Append the server as a top-level entry.
  5171.             class FakeEntry:
  5172.                 pass
  5173.             toplevel = FakeEntry ()
  5174.             toplevel.smbc_type = pysmb.smbc.SERVER
  5175.             toplevel.name = host
  5176.             toplevel.comment = ''
  5177.             iter = store.append (None, [toplevel])
  5178.             i = store.append (iter)
  5179.  
  5180.             # Now expand it.
  5181.             path = store.get_path (iter)
  5182.             self.tvSMBBrowser.expand_row (path, 0)
  5183.  
  5184.         self.ready(self.SMBBrowseDialog)
  5185.  
  5186.         if store.get_iter_first () == None:
  5187.             self.SMBBrowseDialog.hide ()
  5188.             show_info_dialog (_("No Print Shares"),
  5189.                               _("There were no print shares found.  "
  5190.                                 "Please check that the Samba service is "
  5191.                                 "marked as trusted in your firewall "
  5192.                                 "configuration.") + '\n\n' +
  5193.                               TEXT_start_firewall_tool,
  5194.                               parent=self.NewPrinterWindow)
  5195.  
  5196.     def smb_select_function (self, path):
  5197.         """Don't allow this path to be selected unless it is a leaf."""
  5198.         iter = self.smb_store.get_iter (path)
  5199.         return not self.smb_store.iter_has_child (iter)
  5200.  
  5201.     def smbbrowser_cell_share (self, column, cell, model, iter):
  5202.         entry = model.get_value (iter, 0)
  5203.         share = ''
  5204.         if entry != None:
  5205.             share = entry.name
  5206.         cell.set_property ('text', share)
  5207.  
  5208.     def smbbrowser_cell_comment (self, column, cell, model, iter):
  5209.         entry = model.get_value (iter, 0)
  5210.         comment = ''
  5211.         if entry != None:
  5212.             comment = entry.comment
  5213.         cell.set_property ('text', comment)
  5214.  
  5215.     def on_tvSMBBrowser_row_activated (self, view, path, column):
  5216.         """Handle double-clicks in the SMB tree view."""
  5217.         store = self.smb_store
  5218.         iter = store.get_iter (path)
  5219.         entry = store.get_value (iter, 0)
  5220.         if entry and entry.smbc_type == pysmb.smbc.PRINTER_SHARE:
  5221.             # This is a share, not a host.
  5222.             self.btnSMBBrowseOk.clicked ()
  5223.             return
  5224.  
  5225.         if view.row_expanded (path):
  5226.             view.collapse_row (path)
  5227.         else:
  5228.             self.on_tvSMBBrowser_row_expanded (view, iter, path)
  5229.  
  5230.     def on_tvSMBBrowser_row_expanded (self, view, iter, path):
  5231.         """Handler for expanding a row in the SMB tree view."""
  5232.         model = view.get_model ()
  5233.         entry = model.get_value (iter, 0)
  5234.         if entry == None:
  5235.             return
  5236.  
  5237.         if entry.smbc_type == pysmb.smbc.WORKGROUP:
  5238.             # Workgroup
  5239.             # Be careful though: if there is a server with the
  5240.             # same name as the workgroup we will get a list of its
  5241.             # shares, not the workgroup's servers.
  5242.             try:
  5243.                 if self.expanding_row:
  5244.                     return
  5245.             except:
  5246.                 self.expanding_row = 1
  5247.  
  5248.             self.busy (self.SMBBrowseDialog)
  5249.             uri = "smb://%s/" % entry.name
  5250.             debug = 0
  5251.             if get_debugging ():
  5252.                 debug = 10
  5253.             smbc_auth = pysmb.AuthContext (self.SMBBrowseDialog)
  5254.             ctx = pysmb.smbc.Context (debug=debug,
  5255.                                       auth_fn=smbc_auth.callback)
  5256.             entries = []
  5257.             try:
  5258.                 while smbc_auth.perform_authentication () > 0:
  5259.                     try:
  5260.                         entries = ctx.opendir (uri).getdents ()
  5261.                     except Exception, e:
  5262.                         smbc_auth.failed (e)
  5263.             except RuntimeError, (e, s):
  5264.                 if e != errno.ENOENT:
  5265.                     debugprint ("Runtime error: %s" % repr ((e, s)))
  5266.             except:
  5267.                 nonfatalException()
  5268.  
  5269.             while model.iter_has_child (iter):
  5270.                 i = model.iter_nth_child (iter, 0)
  5271.                 model.remove (i)
  5272.  
  5273.             for entry in entries:
  5274.                 if entry.smbc_type in [pysmb.smbc.SERVER,
  5275.                                        pysmb.smbc.PRINTER_SHARE]:
  5276.                     i = model.append (iter, [entry])
  5277.                 if entry.smbc_type == pysmb.smbc.SERVER:
  5278.                     n = model.append (i)
  5279.  
  5280.             view.expand_row (path, 0)
  5281.             del self.expanding_row
  5282.             self.ready (self.SMBBrowseDialog)
  5283.  
  5284.         elif entry.smbc_type == pysmb.smbc.SERVER:
  5285.             # Server
  5286.             try:
  5287.                 if self.expanding_row:
  5288.                     return
  5289.             except:
  5290.                 self.expanding_row = 1
  5291.  
  5292.             self.busy (self.SMBBrowseDialog)
  5293.             uri = "smb://%s/" % entry.name
  5294.             debug = 0
  5295.             if get_debugging ():
  5296.                 debug = 10
  5297.             smbc_auth = pysmb.AuthContext (self.SMBBrowseDialog)
  5298.             ctx = pysmb.smbc.Context (debug=debug,
  5299.                                       auth_fn=smbc_auth.callback)
  5300.             shares = []
  5301.             try:
  5302.                 while smbc_auth.perform_authentication () > 0:
  5303.                     try:
  5304.                         shares = ctx.opendir (uri).getdents ()
  5305.                     except Exception, e:
  5306.                         smbc_auth.failed (e)
  5307.             except RuntimeError, (e, s):
  5308.                 if e != errno.EACCES and e != errno.EPERM:
  5309.                     debugprint ("Runtime error: %s" % repr ((e, s)))
  5310.             except:
  5311.                 nonfatalException()
  5312.  
  5313.             while model.iter_has_child (iter):
  5314.                 i = model.iter_nth_child (iter, 0)
  5315.                 model.remove (i)
  5316.  
  5317.             for share in shares:
  5318.                 if share.smbc_type == pysmb.smbc.PRINTER_SHARE:
  5319.                     i = model.append (iter, [share])
  5320.                     debugprint (repr (share))
  5321.  
  5322.             view.expand_row (path, 0)
  5323.             del self.expanding_row
  5324.             self.ready (self.SMBBrowseDialog)
  5325.  
  5326.     def on_entSMBURI_changed (self, ent):
  5327.         uri = ent.get_text ()
  5328.         (group, host, share, user, password) = SMBURI (uri=uri).separate ()
  5329.         if user:
  5330.             self.entSMBUsername.set_text (user)
  5331.         if password:
  5332.             self.entSMBPassword.set_text (password)
  5333.         if user or password:
  5334.             uri = SMBURI (group=group, host=host, share=share).get_uri ()
  5335.             ent.set_text(uri)
  5336.             self.rbtnSMBAuthSet.set_active(True)
  5337.         elif self.entSMBUsername.get_text () == '':
  5338.             self.rbtnSMBAuthPrompt.set_active(True)
  5339.  
  5340.         self.btnSMBVerify.set_sensitive(bool(uri))
  5341.         self.setNPButtons ()
  5342.  
  5343.     def on_tvSMBBrowser_cursor_changed(self, widget):
  5344.         store, iter = self.tvSMBBrowser.get_selection().get_selected()
  5345.         is_share = False
  5346.         if iter:
  5347.             entry = store.get_value (iter, 0)
  5348.             if entry:
  5349.                 is_share = entry.smbc_type == pysmb.smbc.PRINTER_SHARE
  5350.  
  5351.         self.btnSMBBrowseOk.set_sensitive(iter != None and is_share)
  5352.  
  5353.     def on_btnSMBBrowse_clicked(self, button):
  5354.         self.btnSMBBrowseOk.set_sensitive(False)
  5355.         self.SMBBrowseDialog.show()
  5356.         self.browse_smb_hosts()
  5357.  
  5358.     def on_btnSMBBrowseOk_clicked(self, button):
  5359.         store, iter = self.tvSMBBrowser.get_selection().get_selected()
  5360.         is_share = False
  5361.         if iter:
  5362.             entry = store.get_value (iter, 0)
  5363.             if entry:
  5364.                 is_share = entry.smbc_type == pysmb.smbc.PRINTER_SHARE
  5365.  
  5366.         if not iter or not is_share:
  5367.             self.SMBBrowseDialog.hide()
  5368.             return
  5369.  
  5370.         parent_iter = store.iter_parent (iter)
  5371.         domain_iter = store.iter_parent (parent_iter)
  5372.         share = store.get_value (iter, 0)
  5373.         host = store.get_value (parent_iter, 0)
  5374.         if domain_iter:
  5375.             group = store.get_value (domain_iter, 0).name
  5376.         else:
  5377.             group = ''
  5378.         uri = SMBURI (group=group,
  5379.                       host=host.name,
  5380.                       share=share.name).get_uri ()
  5381.  
  5382.         self.entSMBUsername.set_text ('')
  5383.         self.entSMBPassword.set_text ('')
  5384.         self.entSMBURI.set_text (uri)
  5385.  
  5386.         self.SMBBrowseDialog.hide()
  5387.  
  5388.     def on_btnSMBBrowseCancel_clicked(self, widget, *args):
  5389.         self.SMBBrowseDialog.hide()
  5390.  
  5391.     def on_btnSMBBrowseRefresh_clicked(self, button):
  5392.         self.browse_smb_hosts()
  5393.  
  5394.     def on_rbtnSMBAuthSet_toggled(self, widget):
  5395.         self.tblSMBAuth.set_sensitive(widget.get_active())
  5396.  
  5397.     def on_btnSMBVerify_clicked(self, button):
  5398.         uri = self.entSMBURI.get_text ()
  5399.         (group, host, share, u, p) = SMBURI (uri=uri).separate ()
  5400.         user = ''
  5401.         passwd = ''
  5402.         reason = None
  5403.         auth_set = self.rbtnSMBAuthSet.get_active()
  5404.         if auth_set:
  5405.             user = self.entSMBUsername.get_text ()
  5406.             passwd = self.entSMBPassword.get_text ()
  5407.  
  5408.         accessible = False
  5409.         canceled = False
  5410.         self.busy ()
  5411.         try:
  5412.             debug = 0
  5413.             if get_debugging ():
  5414.                 debug = 10
  5415.  
  5416.             if auth_set:
  5417.                 # No prompting.
  5418.                 def do_auth (svr, shr, wg, un, pw):
  5419.                     return (group, user, passwd)
  5420.                 ctx = pysmb.smbc.Context (debug=debug, auth_fn=do_auth)
  5421.                 f = ctx.open ("smb://%s/%s" % (host, share),
  5422.                               os.O_RDWR, 0777)
  5423.                 accessible = True
  5424.             else:
  5425.                 # May need to prompt.
  5426.                 smbc_auth = pysmb.AuthContext (self.NewPrinterWindow,
  5427.                                                workgroup=group,
  5428.                                                user=user,
  5429.                                                passwd=passwd)
  5430.                 ctx = pysmb.smbc.Context (debug=debug,
  5431.                                           auth_fn=smbc_auth.callback)
  5432.                 while smbc_auth.perform_authentication () > 0:
  5433.                     try:
  5434.                         f = ctx.open ("smb://%s/%s" % (host, share),
  5435.                                       os.O_RDWR, 0777)
  5436.                         accessible = True
  5437.                     except Exception, e:
  5438.                         smbc_auth.failed (e)
  5439.  
  5440.                 if not accessible:
  5441.                     canceled = True
  5442.         except RuntimeError, (e, s):
  5443.             debugprint ("Error accessing share: %s" % repr ((e, s)))
  5444.             reason = s
  5445.         except:
  5446.             nonfatalException()
  5447.         self.ready ()
  5448.  
  5449.         if accessible:
  5450.             show_info_dialog (_("Print Share Verified"),
  5451.                               _("This print share is accessible."),
  5452.                               parent=self.NewPrinterWindow)
  5453.             return
  5454.  
  5455.         if not canceled:
  5456.             text = _("This print share is not accessible.")
  5457.             if reason:
  5458.                 text = reason
  5459.             show_error_dialog (_("Print Share Inaccessible"), text,
  5460.                                parent=self.NewPrinterWindow)
  5461.  
  5462.     ### IPP Browsing
  5463.     def update_IPP_URI_label(self):
  5464.         hostname = self.entNPTIPPHostname.get_text ()
  5465.         queue = self.entNPTIPPQueuename.get_text ()
  5466.         valid = len (hostname) > 0 and queue != '/printers/'
  5467.  
  5468.         if valid:
  5469.             uri = "%s://%s%s" % (self.device.type, hostname, queue)
  5470.             self.lblIPPURI.set_text (uri)
  5471.             self.lblIPPURI.show ()
  5472.             self.entNPTIPPQueuename.show ()
  5473.         else:
  5474.             self.lblIPPURI.hide ()
  5475.  
  5476.         self.btnIPPVerify.set_sensitive (valid)
  5477.         self.setNPButtons ()
  5478.  
  5479.     def on_entNPTIPPHostname_changed(self, ent):
  5480.         valid = len (ent.get_text ()) > 0
  5481.         self.update_IPP_URI_label ()
  5482.  
  5483.     def on_entNPTIPPQueuename_changed(self, ent):
  5484.         self.update_IPP_URI_label ()
  5485.  
  5486.     def on_btnIPPVerify_clicked(self, button):
  5487.         uri = self.lblIPPURI.get_text ()
  5488.         (scheme, rest) = urllib.splittype (uri)
  5489.         (hostport, rest) = urllib.splithost (rest)
  5490.         verified = False
  5491.         if hostport != None:
  5492.             (host, port) = urllib.splitnport (hostport, defport=631)
  5493.             if uri.startswith ("https:"):
  5494.                 encryption = cups.HTTP_ENCRYPT_ALWAYS
  5495.             else:
  5496.                 encryption = cups.HTTP_ENCRYPT_IF_REQUESTED
  5497.  
  5498.             def get_attributes():
  5499.                 c = cups.Connection (host=host, port=port,
  5500.                                      encryption=encryption)
  5501.                 return c.getPrinterAttributes (uri=uri)
  5502.                 
  5503.             op = TimedOperation (get_attributes)
  5504.             self.lblWait.set_markup ('<span weight="bold" size="larger">' +
  5505.                                      _('Verifying') + '</span>\n\n' +
  5506.                                      _('Verifying printer'))
  5507.             self.WaitWindow.set_transient_for (self.NewPrinterWindow)
  5508.             self.WaitWindow.show ()
  5509.             self.busy (self.WaitWindow)
  5510.             source = gobject.timeout_add (10000, op.cancel)
  5511.             try:
  5512.                 attributes = op.run ()
  5513.                 verified = True
  5514.             except OperationCanceled:
  5515.                 pass
  5516.             except cups.IPPError, (e, msg):
  5517.                 debugprint ("Failed to get attributes: %s (%d)" % (msg, e))
  5518.             except:
  5519.                 nonfatalException ()
  5520.  
  5521.             gobject.source_remove (source)
  5522.             self.WaitWindow.hide ()
  5523.         else:
  5524.             debugprint (uri)
  5525.  
  5526.         if verified:
  5527.             show_info_dialog (_("Print Share Verified"),
  5528.                               _("This print share is accessible."),
  5529.                               parent=self.NewPrinterWindow)
  5530.         else:
  5531.             show_error_dialog (_("Inaccessible"),
  5532.                                _("This print share is not accessible."),
  5533.                                self.NewPrinterWindow)
  5534.  
  5535.     def on_expNPDeviceURIs_expanded (self, widget, UNUSED):
  5536.         # When the expanded is not expanded we want its packing to be
  5537.         # 'expand = false' so that it aligns at the bottom (it packs
  5538.         # to the end of its vbox).  But when it is expanded we'd like
  5539.         # it to expand with the window.
  5540.         #
  5541.         # Adjust its 'expand' packing state depending on whether the
  5542.         # widget is expanded.
  5543.  
  5544.         parent = widget.get_parent ()
  5545.         (expand, fill,
  5546.          padding, pack_type) = parent.query_child_packing (widget)
  5547.         expand = widget.get_expanded ()
  5548.         parent.set_child_packing (widget, expand, fill,
  5549.                                   padding, pack_type)
  5550.  
  5551.     def device_row_separator_fn (self, model, iter):
  5552.         return model.get_value (iter, 2)
  5553.  
  5554.     def device_row_activated (self, view, path, column):
  5555.         if view.row_expanded (path):
  5556.             view.collapse_row (path)
  5557.         else:
  5558.             view.expand_row (path, False)
  5559.  
  5560.     def device_select_function (self, path):
  5561.         """
  5562.         Allow this path to be selected as long as there
  5563.         is a device associated with it.  Otherwise, expand or collapse it.
  5564.         """
  5565.         model = self.tvNPDevices.get_model ()
  5566.         iter = model.get_iter (path)
  5567.         if model.get_value (iter, 1) != None:
  5568.             return True
  5569.  
  5570.         self.device_row_activated (self.tvNPDevices, path, None)
  5571.         return False
  5572.  
  5573.     def on_tvNPDevices_cursor_changed(self, widget):
  5574.         path, column = widget.get_cursor ()
  5575.         if path == None:
  5576.             return
  5577.  
  5578.         model = widget.get_model ()
  5579.         iter = model.get_iter (path)
  5580.         physicaldevice = model.get_value (iter, 1)
  5581.         if physicaldevice == None:
  5582.             return
  5583.         for device in physicaldevice.get_devices ():
  5584.             if device.type == "parallel":
  5585.                 device.menuentry = _("Parallel Port")
  5586.             elif device.type == "serial":
  5587.                 device.menuentry = _("Serial Port")
  5588.             elif device.type == "usb":
  5589.                 device.menuentry = _("USB")
  5590.             elif device.type == "bluetooth":
  5591.                 device.menuentry = _("Bluetooth")
  5592.             elif device.type == "hp":
  5593.                 device.menuentry = _("HP Linux Imaging and Printing (HPLIP)")
  5594.             elif device.type == "hpfax":
  5595.                 device.menuentry = _("Fax") + " - " + \
  5596.                     _("HP Linux Imaging and Printing (HPLIP)")
  5597.             elif device.type == "hal":
  5598.                 device.menuentry = _("Hardware Abstraction Layer (HAL)")
  5599.             elif device.type == "socket":
  5600.                 device.menuentry = _("AppSocket/HP JetDirect")
  5601.             elif device.type == "lpd":
  5602.                 (scheme, rest) = urllib.splittype (device.uri)
  5603.                 (hostport, rest) = urllib.splithost (rest)
  5604.                 (queue, rest) = urllib.splitquery (rest)
  5605.                 if queue[0] == '/':
  5606.                     queue = queue[1:]
  5607.  
  5608.                 if queue != '':
  5609.                     device.menuentry = _("LPD/LPR queue '%s'") % queue
  5610.                 else:
  5611.                     device.menuentry = _("LPD/LPR queue")
  5612.  
  5613.             elif device.type == "smb":
  5614.                 device.menuentry = _("Windows Printer via SAMBA")
  5615.             elif device.type == "ipp":
  5616.                 device.menuentry = _("IPP")
  5617.             elif device.type == "http" or device.type == "https":
  5618.                 device.menuentry = _("HTTP")
  5619.             elif device.type == "dnssd" or device.type == "mdns":
  5620.                 (scheme, rest) = urllib.splittype (device.uri)
  5621.                 (name, rest) = urllib.splithost (rest)
  5622.                 (cupsqueue, rest) = urllib.splitquery (rest)
  5623.                 if cupsqueue[0] == '/':
  5624.                     cupsqueue = cupsqueue[1:]
  5625.                 if cupsqueue == 'cups':
  5626.                     device.menuentry = _("Remote CUPS printer via DNS-SD")
  5627.                 else:
  5628.                     protocol = None
  5629.                     if name.find("._ipp") != -1:
  5630.                         protocol = "IPP"
  5631.                     elif name.find("._printer") != -1:
  5632.                         protocol = "LPD"
  5633.                     elif name.find("._pdl-datastream") != -1:
  5634.                         protocol = "AppSocket/JetDirect"
  5635.                     if protocol != None:
  5636.                         device.menuentry = \
  5637.                             _("%s network printer via DNS-SD") % protocol
  5638.                     else:
  5639.                         device.menuentry = \
  5640.                             _("Network printer via DNS-SD")
  5641.             else:
  5642.                 device.menuentry = device.uri
  5643.  
  5644.         model = gtk.ListStore (str,                    # URI description
  5645.                                gobject.TYPE_PYOBJECT)  # cupshelpers.Device
  5646.         self.tvNPDeviceURIs.set_model (model)
  5647.  
  5648.         # If this is a network device, check whether HPLIP can drive it.
  5649.         if physicaldevice.get_data ('checked-hplip') != True:
  5650.             hp_drivable = False
  5651.             is_network = False
  5652.             remotecups = False
  5653.             host = None
  5654.             device_dict = { 'device-class': 'network' }
  5655.             if physicaldevice._network_host:
  5656.                 host = physicaldevice._network_host
  5657.             for device in physicaldevice.get_devices ():
  5658.                 if device.type == "hp":
  5659.                     # We already know that HPLIP can drive this device.
  5660.                     hp_drivable = True
  5661.                     break
  5662.                 elif device.type in ["socket", "lpd", "ipp", "dnssd", "mdns"]:
  5663.                     # This is a network printer.
  5664.                     if host == None and device.type in ["socket", "lpd", "ipp"]:
  5665.                         (scheme, rest) = urllib.splittype (device.uri)
  5666.                         (hostport, rest) = urllib.splithost (rest)
  5667.                         if hostport != None:
  5668.                             (host, port) = urllib.splitport (hostport)
  5669.                     if host:
  5670.                         is_network = True
  5671.                         remotecups = ((device.uri.startswith('dnssd:') or \
  5672.                                        device.uri.startswith('mdns:')) and \
  5673.                                       device.uri.endswith('/cups'))
  5674.                         if (not device.make_and_model or \
  5675.                             device.make_and_model == "Unknown") and not \
  5676.                            remotecups:
  5677.                             self.getNetworkPrinterMakeModel(host=host,
  5678.                                                             device=device)
  5679.                         device_dict['device-info'] = device.info
  5680.                         device_dict['device-make-and-model'] = (device.
  5681.                                                                 make_and_model)
  5682.                         device_dict['device-id'] = device.id
  5683.  
  5684.             if not hp_drivable and is_network and not remotecups:
  5685.                 hplipuri = self.get_hplip_uri_for_network_printer (host,
  5686.                                                                    "print")
  5687.                 if hplipuri:
  5688.                     dev = cupshelpers.Device (hplipuri, **device_dict)
  5689.                     dev.menuentry = "HP Linux Imaging and Printing (HPLIP)"
  5690.                     physicaldevice.add_device (dev)
  5691.  
  5692.                     # Now check to see if we can also send faxes using
  5693.                     # this device.
  5694.                     faxuri = self.get_hplip_uri_for_network_printer (host,
  5695.                                                                      "fax")
  5696.                     if faxuri:
  5697.                         faxdevid = self.get_hpfax_device_id (faxuri)
  5698.                         device_dict['device-id'] = faxdevid
  5699.                         device_dict['device-info'] = _("Fax")
  5700.                         faxdev = cupshelpers.Device (faxuri, **device_dict)
  5701.                         faxdev.menuentry = _("Fax") + " - " + \
  5702.                             "HP Linux Imaging and Printing (HPLIP)"
  5703.                         physicaldevice.add_device (faxdev)
  5704.  
  5705.                 physicaldevice.set_data ('checked-hplip', True)
  5706.  
  5707.         # Fill the list of connections for this device.
  5708.         n = 0
  5709.         for device in physicaldevice.get_devices ():
  5710.             model.append ((device.menuentry, device))
  5711.             n += 1
  5712.         column = self.tvNPDeviceURIs.get_column (0)
  5713.         self.tvNPDeviceURIs.set_cursor (0, column)
  5714.         if n > 1:
  5715.             self.expNPDeviceURIs.show_all ()
  5716.         else:
  5717.             self.expNPDeviceURIs.hide ()
  5718.  
  5719.     def on_tvNPDeviceURIs_cursor_changed(self, widget):
  5720.         path, column = widget.get_cursor ()
  5721.         if path == None:
  5722.             return
  5723.  
  5724.         model = widget.get_model ()
  5725.         iter = model.get_iter (path)
  5726.         device = model.get_value(iter, 1)
  5727.         self.device = device
  5728.         self.lblNPDeviceDescription.set_text ('')
  5729.         page = self.new_printer_device_tabs.get(device.type, 1)
  5730.         self.ntbkNPType.set_current_page(page)
  5731.  
  5732.         location = ''
  5733.         type = device.type
  5734.         url = device.uri.split(":", 1)[-1]
  5735.         if page == 0:
  5736.             # This is the "no options" page, with just a label to describe
  5737.             # the selected device.
  5738.             if device.type == "parallel":
  5739.                 text = _("A printer connected to the parallel port.")
  5740.             elif device.type == "usb":
  5741.                 text = _("A printer connected to a USB port.")
  5742.             elif device.type == "bluetooth":
  5743.                 text = _("A printer connected via Bluetooth.")
  5744.             elif device.type == "hp":
  5745.                 text = _("HPLIP software driving a printer, "
  5746.                          "or the printer function of a multi-function device.")
  5747.             elif device.type == "hpfax":
  5748.                 text = _("HPLIP software driving a fax machine, "
  5749.                          "or the fax function of a multi-function device.")
  5750.             elif device.type == "hal":
  5751.                 text = _("Local printer detected by the "
  5752.                          "Hardware Abstraction Layer (HAL).")
  5753.             elif device.type == "dnssd" or device.type == "mdns":
  5754.                 (scheme, rest) = urllib.splittype (device.uri)
  5755.                 (name, rest) = urllib.splithost (rest)
  5756.                 (cupsqueue, rest) = urllib.splitquery (rest)
  5757.                 if cupsqueue[0] == '/':
  5758.                     cupsqueue = cupsqueue[1:]
  5759.                 if cupsqueue == 'cups':
  5760.                     text = _("Remote CUPS printer via DNS-SD")
  5761.                 else:
  5762.                     protocol = None
  5763.                     if name.find("._ipp") != -1:
  5764.                         protocol = "IPP"
  5765.                     elif name.find("._printer") != -1:
  5766.                         protocol = "LPD"
  5767.                     elif name.find("._pdl-datastream") != -1:
  5768.                         protocol = "AppSocket/JetDirect"
  5769.                     if protocol != None:
  5770.                         text = _("%s network printer via DNS-SD") % protocol
  5771.                     else:
  5772.                         text = _("Network printer via DNS-SD")
  5773.             else:
  5774.                 text = device.uri
  5775.  
  5776.             self.lblNPDeviceDescription.set_text (text)
  5777.         elif device.type=="socket":
  5778.             (scheme, rest) = urllib.splittype (device.uri)
  5779.             host = ''
  5780.             port = 9100
  5781.             if scheme == "socket":
  5782.                 (hostport, rest) = urllib.splithost (rest)
  5783.                 (host, port) = urllib.splitnport (hostport, defport=port)
  5784.                 debugprint ("socket: host is %s, port is %s" % (host,
  5785.                                                                 repr (port)))
  5786.                 location = host
  5787.             self.entNPTDirectJetHostname.set_text (host)
  5788.             self.entNPTDirectJetPort.set_text (str (port))
  5789.         elif device.type=="serial":
  5790.             if not device.is_class:
  5791.                 options = device.uri.split("?")[1]
  5792.                 options = options.split("+")
  5793.                 option_dict = {}
  5794.                 for option in options:
  5795.                     name, value = option.split("=")
  5796.                     option_dict[name] = value
  5797.  
  5798.                 for widget, name, optionvalues in (
  5799.                     (self.cmbNPTSerialBaud, "baud", None),
  5800.                     (self.cmbNPTSerialBits, "bits", None),
  5801.                     (self.cmbNPTSerialParity, "parity",
  5802.                      ["none", "odd", "even"]),
  5803.                     (self.cmbNPTSerialFlow, "flow",
  5804.                      ["none", "soft", "hard", "hard"])):
  5805.                     if option_dict.has_key(name): # option given in URI?
  5806.                         if optionvalues is None: # use text in widget
  5807.                             model = widget.get_model()
  5808.                             iter = model.get_iter_first()
  5809.                             nr = 0
  5810.                             while iter:
  5811.                                 value = model.get(iter,0)[0]
  5812.                                 if value == option_dict[name]:
  5813.                                     widget.set_active(nr)
  5814.                                     break
  5815.                                 iter = model.iter_next(iter)
  5816.                                 nr += 1
  5817.                         else: # use optionvalues
  5818.                             nr = optionvalues.index(
  5819.                                 option_dict[name])
  5820.                             widget.set_active(nr+1) # compensate "Default"
  5821.                     else:
  5822.                         widget.set_active(0)
  5823.  
  5824.         # XXX FILL TABS FOR VALID DEVICE URIs
  5825.         elif device.type in ("ipp", "http", "https"):
  5826.             if device.uri.find (":") != -1:
  5827.                 match = re.match ("(ipp|https?)://([^/]+)(.*)", device.uri)
  5828.                 if match:
  5829.                     server = match.group (2)
  5830.                     printer = match.group (3)
  5831.                 else:
  5832.                     server = ""
  5833.                     printer = ""
  5834.  
  5835.                 self.entNPTIPPHostname.set_text(server)
  5836.                 self.entNPTIPPQueuename.set_text(printer)
  5837.                 self.lblIPPURI.set_text(device.uri)
  5838.                 self.lblIPPURI.show()
  5839.                 self.entNPTIPPQueuename.show()
  5840.                 location = server
  5841.             else:
  5842.                 self.entNPTIPPHostname.set_text('')
  5843.                 self.entNPTIPPQueuename.set_text('/printers/')
  5844.                 self.entNPTIPPQueuename.show()
  5845.                 self.lblIPPURI.hide()
  5846.         elif device.type=="lpd":
  5847.             self.cmbentNPTLpdHost.child.set_text ('')
  5848.             self.cmbentNPTLpdQueue.child.set_text ('')
  5849.             self.cmbentNPTLpdQueue.get_model().clear ()
  5850.             self.btnNPTLpdProbe.set_sensitive (False)
  5851.             if len (device.uri) > 6:
  5852.                 host = device.uri[6:]
  5853.                 i = host.find ("/")
  5854.                 if i != -1:
  5855.                     printer = host[i + 1:]
  5856.                     host = host[:i]
  5857.                 else:
  5858.                     printer = ""
  5859.                 self.cmbentNPTLpdHost.child.set_text (host)
  5860.                 self.cmbentNPTLpdQueue.child.set_text (printer)
  5861.                 location = host
  5862.                 self.btnNPTLpdProbe.set_sensitive (True)
  5863.         elif device.uri == "smb":
  5864.             self.entSMBURI.set_text('')
  5865.             self.btnSMBVerify.set_sensitive(False)
  5866.         elif device.type == "smb":
  5867.             self.entSMBUsername.set_text ('')
  5868.             self.entSMBPassword.set_text ('')
  5869.             self.entSMBURI.set_text(device.uri[6:])
  5870.             self.btnSMBVerify.set_sensitive(True)
  5871.         else:
  5872.             self.entNPTDevice.set_text(device.uri)
  5873.  
  5874.         try:
  5875.             if len (location) == 0 and self.device.device_class == "direct":
  5876.                 # Set location to the name of this host.
  5877.                 if (self.mainapp.connect_server == 'localhost' or
  5878.                     self.mainapp.connect_server[0] == '/'):
  5879.                     u = os.uname ()
  5880.                     location = u[1]
  5881.                 else:
  5882.                     location = self.mainapp.connect_server
  5883.  
  5884.             # Pre-fill location field.
  5885.             self.entNPLocation.set_text (location)
  5886.         except:
  5887.             nonfatalException ()
  5888.  
  5889.         self.setNPButtons()
  5890.  
  5891.     def on_cmbentNPTLpdHost_changed(self, cmbent):
  5892.         hostname = cmbent.get_active_text()
  5893.         self.btnNPTLpdProbe.set_sensitive (len (hostname) > 0)
  5894.         self.setNPButtons()
  5895.  
  5896.     def on_btnNPTLpdProbe_clicked(self, button):
  5897.         # read hostname, probe, fill printer names
  5898.         hostname = self.cmbentNPTLpdHost.get_active_text()
  5899.         server = probe_printer.LpdServer(hostname)
  5900.  
  5901.         self.lblWait.set_markup ('<span weight="bold" size="larger">' +
  5902.                                  _('Searching') + '</span>\n\n' +
  5903.                                  _('Searching for printers'))
  5904.         self.WaitWindow.set_transient_for (self.NewPrinterWindow)
  5905.         self.WaitWindow.show_now ()
  5906.         self.busy (self.WaitWindow)
  5907.         printers = server.probe()
  5908.         self.WaitWindow.hide ()
  5909.  
  5910.         model = self.cmbentNPTLpdQueue.get_model()
  5911.         model.clear()
  5912.         for printer in printers:
  5913.             self.cmbentNPTLpdQueue.append_text(printer)
  5914.         if printers:
  5915.             self.cmbentNPTLpdQueue.set_active(0)
  5916.  
  5917.     ### Find Network Printer
  5918.     def on_entNPTNetworkHostname_changed(self, ent):
  5919.         s = ent.get_text ()
  5920.         self.btnNetworkFind.set_sensitive (len (s) > 0)
  5921.         self.lblNetworkFindNotFound.hide ()
  5922.         self.setNPButtons ()
  5923.  
  5924.     def on_btnNetworkFind_clicked(self, button):
  5925.         host = self.entNPTNetworkHostname.get_text ()
  5926.  
  5927.         def found_callback (new_device):
  5928.             glib.idle_add (self.found_network_printer_callback, new_device)
  5929.  
  5930.         self.btnNetworkFind.set_sensitive (False)
  5931.         self.entNPTNetworkHostname.set_sensitive (False)
  5932.         self.network_found = 0
  5933.         self.lblNetworkFindSearching.show_all ()
  5934.         finder = probe_printer.PrinterFinder ()
  5935.         self.imgProcessWorking.show ()
  5936.         self.spinner.start ()
  5937.         finder.find (host, found_callback)
  5938.  
  5939.     def found_network_printer_callback (self, new_device):
  5940.         if new_device:
  5941.             self.network_found += 1
  5942.             dev = PhysicalDevice (new_device)
  5943.             try:
  5944.                 i = self.devices.index (dev)
  5945.                 self.devices[i].add_device (new_device)
  5946.  
  5947.                 (path, column) = self.tvNPDevices.get_cursor ()
  5948.                 model = self.tvNPDevices.get_model ()
  5949.                 iter = model.get_iter (path)
  5950.                 if model.get_value (iter, 1) == self.devices[i]:
  5951.                     self.on_tvNPDevices_cursor_changed (self.tvNPDevices)
  5952.             except ValueError:
  5953.                 dev.set_data ('checked-hplip', True)
  5954.                 self.devices.append (dev)
  5955.                 self.devices.sort ()
  5956.                 model = self.tvNPDevices.get_model ()
  5957.                 iter = model.insert_before (None, self.devices_find_nw_iter,
  5958.                                             row=[dev.get_info (), dev, False])
  5959.  
  5960.             # If this is the first one we've found, select it.
  5961.             if self.network_found == 1:
  5962.                 path = model.get_path (iter)
  5963.                 self.tvNPDevices.set_cursor (path)
  5964.         else:
  5965.             self.imgProcessWorking.hide ()
  5966.             self.spinner.stop ()
  5967.             self.lblNetworkFindSearching.hide ()
  5968.             self.entNPTNetworkHostname.set_sensitive (True)
  5969.             self.btnNetworkFind.set_sensitive (True)
  5970.             if self.network_found == 0:
  5971.                 self.lblNetworkFindNotFound.set_markup ('<i>' +
  5972.                                                         _("No printer was "
  5973.                                                           "found at that "
  5974.                                                           "address.") + '</i>')
  5975.                 self.lblNetworkFindNotFound.show ()
  5976.     ###
  5977.  
  5978.     def getDeviceURI(self):
  5979.         type = self.device.type
  5980.         page = self.new_printer_device_tabs.get (type, 1)
  5981.         device = type
  5982.         if page == 0:
  5983.             # The "no options page".  We already have the URI.
  5984.             device = self.device.uri
  5985.         elif type == "socket": # DirectJet
  5986.             host = self.entNPTDirectJetHostname.get_text()
  5987.             port = self.entNPTDirectJetPort.get_text()
  5988.             if host:
  5989.                 device += "://" + host
  5990.                 if port:
  5991.                     device += ":" + port
  5992.         elif type in ("ipp", "http", "https"): # IPP
  5993.             if self.lblIPPURI.get_property('visible'):
  5994.                 device = self.lblIPPURI.get_text()
  5995.         elif type == "lpd": # LPD
  5996.             host = self.cmbentNPTLpdHost.get_active_text()
  5997.             printer = self.cmbentNPTLpdQueue.get_active_text()
  5998.             if host:
  5999.                 device += "://" + host
  6000.                 if printer:
  6001.                     device += "/" + printer
  6002.         elif type == "serial": # Serial
  6003.             options = []
  6004.             for widget, name, optionvalues in (
  6005.                 (self.cmbNPTSerialBaud, "baud", None),
  6006.                 (self.cmbNPTSerialBits, "bits", None),
  6007.                 (self.cmbNPTSerialParity, "parity",
  6008.                  ("none", "odd", "even")),
  6009.                 (self.cmbNPTSerialFlow, "flow",
  6010.                  ("none", "soft", "hard", "hard"))):
  6011.                 nr = widget.get_active()
  6012.                 if nr:
  6013.                     if optionvalues is not None:
  6014.                         option = optionvalues[nr-1]
  6015.                     else:
  6016.                         option = widget.get_active_text()
  6017.                     options.append(name + "=" + option)
  6018.             options = "+".join(options)
  6019.             device =  self.device.uri.split("?")[0] #"serial:/dev/ttyS%s"
  6020.             if options:
  6021.                 device = device + "?" + options
  6022.         elif type == "smb":
  6023.             uri = self.entSMBURI.get_text ()
  6024.             (group, host, share, u, p) = SMBURI (uri=uri).separate ()
  6025.             user = ''
  6026.             password = ''
  6027.             if self.rbtnSMBAuthSet.get_active ():
  6028.                 user = self.entSMBUsername.get_text ()
  6029.                 password = self.entSMBPassword.get_text ()
  6030.             uri = SMBURI (group=group, host=host, share=share,
  6031.                           user=user, password=password).get_uri ()
  6032.             if uri:
  6033.                 device += "://" + uri
  6034.         else:
  6035.             device = self.entNPTDevice.get_text()
  6036.         return device
  6037.  
  6038.     # PPD
  6039.  
  6040.     def on_rbtnNPFoomatic_toggled(self, widget):
  6041.         rbtn1 = self.rbtnNPFoomatic.get_active()
  6042.         rbtn2 = self.rbtnNPPPD.get_active()
  6043.         rbtn3 = self.rbtnNPDownloadableDriverSearch.get_active()
  6044.         self.tvNPMakes.set_sensitive(rbtn1)
  6045.         self.filechooserPPD.set_sensitive(rbtn2)
  6046.  
  6047.         if rbtn1:
  6048.             page = 0
  6049.         if rbtn2:
  6050.             page = 1
  6051.         if rbtn3:
  6052.             page = 2
  6053.         self.ntbkPPDSource.set_current_page (page)
  6054.  
  6055.         if not rbtn3 and self.openprinting_query_handle:
  6056.             # Need to cancel a search in progress.
  6057.             self.openprinting.cancelOperation (self.openprinting_query_handle)
  6058.             self.openprinting_query_handle = None
  6059.             self.btnNPDownloadableDriverSearch_label.set_text (_("Search"))
  6060.             # Clear printer list.
  6061.             model = gtk.ListStore (str, str)
  6062.             combobox = self.cmbNPDownloadableDriverFoundPrinters
  6063.             combobox.set_model (model)
  6064.             combobox.set_sensitive (False)
  6065.  
  6066.         for widget in [self.entNPDownloadableDriverSearch,
  6067.                        self.cmbNPDownloadableDriverFoundPrinters]:
  6068.             widget.set_sensitive(rbtn3)
  6069.         self.btnNPDownloadableDriverSearch.\
  6070.             set_sensitive (rbtn3 and (self.openprinting_query_handle == None))
  6071.  
  6072.         self.setNPButtons()
  6073.  
  6074.     def on_filechooserPPD_selection_changed(self, widget):
  6075.         self.setNPButtons()
  6076.  
  6077.     def on_btnNPDownloadableDriverSearch_clicked(self, widget):
  6078.         if self.openprinting_query_handle != None:
  6079.             self.openprinting.cancelOperation (self.openprinting_query_handle)
  6080.             self.openprinting_query_handle = None
  6081.  
  6082.         widget.set_sensitive (False)
  6083.         label = self.btnNPDownloadableDriverSearch_label
  6084.         label.set_text (_("Searching"))
  6085.         searchterm = self.entNPDownloadableDriverSearch.get_text ()
  6086.         self.openprinting_query_handle = \
  6087.             self.openprinting.searchPrinters (searchterm,
  6088.                                               self.openprinting_printers_found)
  6089.         self.cmbNPDownloadableDriverFoundPrinters.set_sensitive (False)
  6090.  
  6091.     def openprinting_printers_found (self, status, user_data, printers):
  6092.         self.openprinting_query_handle = None
  6093.         button = self.btnNPDownloadableDriverSearch
  6094.         label = self.btnNPDownloadableDriverSearch_label
  6095.         gtk.gdk.threads_enter ()
  6096.         try:
  6097.             label.set_text (_("Search"))
  6098.             button.set_sensitive (True)
  6099.             if status != 0:
  6100.                 # Should report error.
  6101.                 print printers
  6102.                 print traceback.extract_tb(printers[2], limit=None)
  6103.                 gtk.gdk.threads_leave ()
  6104.                 return
  6105.  
  6106.             model = gtk.ListStore (str, str)
  6107.             if len (printers) != 1:
  6108.                 if len (printers) > 1:
  6109.                     first = _("-- Select from search results --")
  6110.                 else:
  6111.                     first = _("-- No matches found --")
  6112.  
  6113.                 iter = model.append (None)
  6114.                 model.set_value (iter, 0, first)
  6115.                 model.set_value (iter, 1, None)
  6116.  
  6117.             sorted_list = []
  6118.             for id, name in printers.iteritems ():
  6119.                 sorted_list.append ((id, name))
  6120.  
  6121.             sorted_list.sort (lambda x, y: cups.modelSort (x[1], y[1]))
  6122.             sought = self.entNPDownloadableDriverSearch.get_text ().lower ()
  6123.             select_index = 0
  6124.             for id, name in sorted_list:
  6125.                 iter = model.append (None)
  6126.                 model.set_value (iter, 0, name)
  6127.                 model.set_value (iter, 1, id)
  6128.                 if name.lower () == sought:
  6129.                     select_index = model.get_path (iter)[0]
  6130.             combobox = self.cmbNPDownloadableDriverFoundPrinters
  6131.             combobox.set_model (model)
  6132.             combobox.set_active (select_index)
  6133.             combobox.set_sensitive (True)
  6134.             self.setNPButtons ()
  6135.         except:
  6136.             nonfatalException()
  6137.         gtk.gdk.threads_leave ()
  6138.  
  6139.     def on_cmbNPDownloadableDriverFoundPrinters_changed(self, widget):
  6140.         self.setNPButtons ()
  6141.  
  6142.         if self.openprinting_query_handle != None:
  6143.             self.openprinting.cancelOperation (self.openprinting_query_handle)
  6144.             self.openprinting_query_handle = None
  6145.             self.drivers_lock.release()
  6146.  
  6147.         model = widget.get_model ()
  6148.         iter = widget.get_active_iter ()
  6149.         if iter:
  6150.             id = model.get_value (iter, 1)
  6151.         else:
  6152.             id = None
  6153.  
  6154.         if id == None:
  6155.             return
  6156.  
  6157.         # A model has been selected, so start the query to find out
  6158.         # which drivers are available.
  6159.         debugprint ("Query drivers for %s" % id)
  6160.         self.drivers_lock.acquire(0)
  6161.         extra_options = dict()
  6162.         if self.DOWNLOADABLE_ONLYPPD:
  6163.             extra_options['onlyppdfiles'] = '1'
  6164.         self.openprinting_query_handle = \
  6165.             self.openprinting.listDrivers (id,
  6166.                                            self.openprinting_drivers_found,
  6167.                                            extra_options=extra_options)
  6168.  
  6169.     def openprinting_drivers_found (self, status, user_data, drivers):
  6170.         if status != 0:
  6171.             # Should report error.
  6172.             print drivers
  6173.             print traceback.extract_tb(drivers[2], limit=None)
  6174.             return
  6175.  
  6176.         self.openprinting_query_handle = None
  6177.         self.downloadable_drivers = drivers
  6178.         debugprint ("Drivers query completed: %s" % drivers.keys ())
  6179.         self.drivers_lock.release()
  6180.  
  6181.     def fillDownloadableDrivers(self):
  6182.         # Clear out the properties.
  6183.         self.lblNPDownloadableDriverSupplier.set_text ('')
  6184.         self.lblNPDownloadableDriverLicense.set_text ('')
  6185.         self.lblNPDownloadableDriverDescription.set_text ('')
  6186.         self.lblNPDownloadableDriverSupportContacts.set_text ('')
  6187.         self.rbtnNPDownloadLicenseNo.set_active (True)
  6188.         self.frmNPDownloadableDriverLicenseTerms.hide ()
  6189.  
  6190.         drivers = self.downloadable_drivers
  6191.         model = gtk.ListStore (str,                     # driver name
  6192.                                gobject.TYPE_PYOBJECT)   # driver data
  6193.         recommended_iter = None
  6194.         first_iter = None
  6195.         for driver in drivers.values ():
  6196.             iter = model.append (None)
  6197.             if first_iter == None:
  6198.                 first_iter = iter
  6199.  
  6200.             model.set_value (iter, 0, driver['name'])
  6201.             model.set_value (iter, 1, driver)
  6202.  
  6203.             if driver['recommended']:
  6204.                 recommended_iter = iter
  6205.  
  6206.         if recommended_iter == None:
  6207.             recommended_iter = first_iter
  6208.  
  6209.         treeview = self.tvNPDownloadableDrivers
  6210.         treeview.set_model (model)
  6211.         if recommended_iter != None:
  6212.             treeview.get_selection ().select_iter (recommended_iter)
  6213.  
  6214.     def on_rbtnNPDownloadLicense_toggled(self, widget):
  6215.         self.setNPButtons ()
  6216.  
  6217.     # PPD from foomatic
  6218.  
  6219.     def fillMakeList(self):
  6220.         makes = self.ppds.getMakes()
  6221.         model = self.tvNPMakes.get_model()
  6222.         model.clear()
  6223.         found = False
  6224.         auto_make_lower = self.auto_make.lower ()
  6225.         for make in makes:
  6226.             iter = model.append((make,))
  6227.             if make.lower() == auto_make_lower:
  6228.                 path = model.get_path(iter)
  6229.                 self.tvNPMakes.set_cursor (path)
  6230.                 self.tvNPMakes.scroll_to_cell(path, None,
  6231.                                               True, 0.5, 0.5)
  6232.                 found = True
  6233.  
  6234.         if not found:
  6235.             self.tvNPMakes.set_cursor (0,)
  6236.             self.tvNPMakes.scroll_to_cell(0, None, True, 0.0, 0.0)
  6237.  
  6238.         # Also pre-fill the OpenPrinting.org search box.
  6239.         search = ''
  6240.         if self.device and self.device.id_dict:
  6241.             devid_dict = self.device.id_dict
  6242.             if devid_dict["MFG"] and devid_dict["MDL"]:
  6243.                 search = devid_dict["MFG"] + " " + devid_dict["MDL"]
  6244.             elif devid_dict["DES"]:
  6245.                 search = devid_dict["DES"]
  6246.             elif devid_dict["MFG"]:
  6247.                 search = devid_dict["MFG"]
  6248.         if search == '' and self.auto_make != None:
  6249.             search += self.auto_make
  6250.             if self.auto_model != None:
  6251.                 search += " " + self.auto_model
  6252.         self.entNPDownloadableDriverSearch.set_text (search)
  6253.  
  6254.     def on_tvNPMakes_cursor_changed(self, tvNPMakes):
  6255.         path, column = tvNPMakes.get_cursor()
  6256.         if path != None:
  6257.             model = tvNPMakes.get_model ()
  6258.             iter = model.get_iter (path)
  6259.             self.NPMake = model.get(iter, 0)[0]
  6260.             self.fillModelList()
  6261.  
  6262.     def fillModelList(self):
  6263.         models = self.ppds.getModels(self.NPMake)
  6264.         model = self.tvNPModels.get_model()
  6265.         model.clear()
  6266.         selected = False
  6267.         is_auto_make = self.NPMake.lower () == self.auto_make.lower ()
  6268.         if is_auto_make:
  6269.             auto_model_lower = self.auto_model.lower ()
  6270.  
  6271.         for pmodel in models:
  6272.             iter = model.append((pmodel,))
  6273.             if is_auto_make and pmodel.lower() == auto_model_lower:
  6274.                 path = model.get_path(iter)
  6275.                 self.tvNPModels.set_cursor (path)
  6276.                 self.tvNPModels.scroll_to_cell(path, None,
  6277.                                                True, 0.5, 0.5)
  6278.                 selected = True
  6279.         if not selected:
  6280.             self.tvNPModels.set_cursor (0,)
  6281.             self.tvNPModels.scroll_to_cell(0, None, True, 0.0, 0.0)
  6282.         self.tvNPModels.columns_autosize()
  6283.  
  6284.     def fillDriverList(self, pmake, pmodel):
  6285.         self.NPModel = pmodel
  6286.         model = self.tvNPDrivers.get_model()
  6287.         model.clear()
  6288.  
  6289.         ppds = self.ppds.getInfoFromModel(pmake, pmodel)
  6290.  
  6291.         self.NPDrivers = self.ppds.orderPPDNamesByPreference(ppds.keys(),
  6292.                                              self.jockey_installed_files) 
  6293.         for i in range (len(self.NPDrivers)):
  6294.             ppd = ppds[self.NPDrivers[i]]
  6295.             driver = ppd["ppd-make-and-model"]
  6296.             driver = driver.replace(" (recommended)", "")
  6297.  
  6298.             try:
  6299.                 lpostfix = " [%s]" % ppd["ppd-natural-language"]
  6300.                 driver += lpostfix
  6301.             except KeyError:
  6302.                 pass
  6303.  
  6304.             if i == 0:
  6305.                 iter = model.append ((driver + _(" (recommended)"),))
  6306.                 path = model.get_path (iter)
  6307.                 self.tvNPDrivers.get_selection().select_path(path)
  6308.                 self.tvNPDrivers.scroll_to_cell(path, None, True, 0.5, 0.0)
  6309.             else:
  6310.                 model.append((driver, ))
  6311.         self.tvNPDrivers.columns_autosize()
  6312.  
  6313.     def on_NPDrivers_query_tooltip(self, tv, x, y, keyboard_mode, tooltip):
  6314.         if keyboard_mode:
  6315.             path = tv.get_cursor()[0]
  6316.             if path is None:
  6317.                 return False
  6318.         else:
  6319.             bin_x, bin_y = tv.convert_widget_to_bin_window_coords(x, y)
  6320.             ret = tv.get_path_at_pos (bin_x, bin_y)
  6321.             if ret is None:
  6322.                 return False
  6323.             path = ret[0]
  6324.  
  6325.         drivername = self.NPDrivers[path[0]]
  6326.         ppddict = self.ppds.getInfoFromPPDName(drivername)
  6327.         markup = ppddict['ppd-make-and-model']
  6328.         if (drivername.startswith ("foomatic:")):
  6329.             markup += " "
  6330.             markup += _("This PPD is generated by foomatic.")
  6331.         tooltip.set_markup(markup)
  6332.         return True
  6333.  
  6334.     def on_tvNPModels_cursor_changed(self, widget):
  6335.         path, column = widget.get_cursor()
  6336.         if path != None:
  6337.             model = widget.get_model ()
  6338.             iter = model.get_iter (path)
  6339.             pmodel = model.get(iter, 0)[0]
  6340.             self.fillDriverList(self.NPMake, pmodel)
  6341.             self.on_tvNPDrivers_cursor_changed(self.tvNPDrivers)
  6342.  
  6343.     def on_tvNPDrivers_cursor_changed(self, widget):
  6344.         self.setNPButtons()
  6345.  
  6346.     def on_tvNPDownloadableDrivers_cursor_changed(self, widget):
  6347.         model, iter = widget.get_selection ().get_selected ()
  6348.         if not iter:
  6349.             path, column = widget.get_cursor()
  6350.             iter = model.get_iter (path)
  6351.         driver = model.get_value (iter, 1)
  6352.         import pprint
  6353.         pprint.pprint (driver)
  6354.         self.ntbkNPDownloadableDriverProperties.set_current_page(1)
  6355.         supplier = driver.get('supplier', _("OpenPrinting"))
  6356.         vendor = self.cbNPDownloadableDriverSupplierVendor
  6357.         active = driver['manufacturersupplied']
  6358.  
  6359.         def set_protect_active (widget, active):
  6360.             widget.set_active (active)
  6361.             widget.set_data ('protect_active', active)
  6362.  
  6363.         set_protect_active (vendor, active)
  6364.         self.lblNPDownloadableDriverSupplier.set_text (supplier)
  6365.  
  6366.         license = driver.get('license', _("Distributable"))
  6367.         patents = self.cbNPDownloadableDriverLicensePatents
  6368.         free = self.cbNPDownloadableDriverLicenseFree
  6369.         set_protect_active (patents, driver['patents'])
  6370.         set_protect_active (free, driver['freesoftware'])
  6371.         self.lblNPDownloadableDriverLicense.set_text (license)
  6372.  
  6373.         description = driver.get('shortdescription', _("None"))
  6374.         self.lblNPDownloadableDriverDescription.set_markup (description)
  6375.  
  6376.         functionality = driver['functionality']
  6377.         for field in ["Graphics", "LineArt", "Photo", "Text"]:
  6378.             key = field.lower ()
  6379.             value = None
  6380.             hs = self.__dict__.get ("hsDownloadableDriverPerf%s" % field)
  6381.             unknown = self.__dict__.get ("lblDownloadableDriverPerf%sUnknown"
  6382.                                          % field)
  6383.             if functionality.has_key (key):
  6384.                 if hs:
  6385.                     try:
  6386.                         value = int (functionality[key])
  6387.                         hs.set_value (value)
  6388.                         hs.show_all ()
  6389.                         unknown.hide ()
  6390.                     except:
  6391.                         pass
  6392.  
  6393.             if value == None:
  6394.                 hs.hide ()
  6395.                 unknown.show_all ()
  6396.         supportcontacts = ""
  6397.         if driver.has_key ('supportcontacts'):
  6398.             for supportentry in driver['supportcontacts']:
  6399.                 if supportentry['name']:
  6400.                     supportcontact = " - " + supportentry['name']
  6401.                     supportcontact_extra = ""
  6402.                     if supportentry['url']:
  6403.                         supportcontact_extra = supportcontact_extra + \
  6404.                             supportentry['url']
  6405.                     if supportentry['level']:
  6406.                         if supportcontact_extra:
  6407.                             supportcontact_extra = supportcontact_extra + _(", ")
  6408.                         supportcontact_extra = supportcontact_extra + \
  6409.                             supportentry['level']
  6410.                     if supportcontact_extra:
  6411.                         supportcontact = supportcontact + \
  6412.                             _("\n(%s)") % supportcontact_extra
  6413.                         if supportcontacts:
  6414.                             supportcontacts = supportcontacts + "\n"
  6415.                         supportcontacts = supportcontacts + supportcontact
  6416.         if not supportcontacts:
  6417.             supportcontacts = _("No support contacts known")
  6418.         self.lblNPDownloadableDriverSupportContacts.set_text (supportcontacts)
  6419.         if driver.has_key ('licensetext'):
  6420.             self.frmNPDownloadableDriverLicenseTerms.show ()
  6421.             terms = driver.get('licensetext', _("Not specified."))
  6422.             self.tvNPDownloadableDriverLicense.get_buffer ().set_text (terms)
  6423.         else:
  6424.             self.frmNPDownloadableDriverLicenseTerms.hide ()
  6425.         if not driver['nonfreesoftware'] and not driver['patents']:
  6426.             self.rbtnNPDownloadLicenseYes.set_active (True)
  6427.             self.rbtnNPDownloadLicenseYes.hide ()
  6428.             self.rbtnNPDownloadLicenseNo.hide ()
  6429.         else:
  6430.             self.rbtnNPDownloadLicenseNo.set_active (True)
  6431.             self.rbtnNPDownloadLicenseYes.show ()
  6432.             self.rbtnNPDownloadLicenseNo.show ()
  6433.             self.frmNPDownloadableDriverLicenseTerms.show ()
  6434.             terms = driver.get('licensetext', _("Not specified."))
  6435.             self.tvNPDownloadableDriverLicense.get_buffer ().set_text (terms)
  6436.  
  6437.         self.setNPButtons()
  6438.  
  6439.     def getNPPPD(self):
  6440.         try:
  6441.             if self.rbtnNPFoomatic.get_active():
  6442.                 model, iter = self.tvNPDrivers.get_selection().get_selected()
  6443.                 nr = model.get_path(iter)[0]
  6444.                 ppd = self.NPDrivers[nr]
  6445.             elif self.rbtnNPPPD.get_active():
  6446.                 ppd = cups.PPD(self.filechooserPPD.get_filename())
  6447.             else:
  6448.                 # PPD of the driver downloaded from OpenPrinting XXX
  6449.                 treeview = self.tvNPDownloadableDrivers
  6450.                 model, iter = treeview.get_selection ().get_selected ()
  6451.                 driver = model.get_value (iter, 1)
  6452.                 if driver.has_key ('ppds'):
  6453.                     # Only need to download a PPD.
  6454.                     if (len(driver['ppds']) > 0):
  6455.                         file_to_download = driver['ppds'][0]
  6456.                         debugprint ("ppd file to download [" + file_to_download+ "]")
  6457.                         file_to_download = file_to_download.strip()
  6458.                         if (len(file_to_download) > 0):
  6459.                             ppdurlobj = urllib.urlopen(file_to_download)
  6460.                             ppdcontent = ppdurlobj.read()
  6461.                             ppdurlobj.close()
  6462.                             (tmpfd, ppdname) = tempfile.mkstemp()
  6463.                             debugprint(ppdname)
  6464.                             ppdfile = os.fdopen(tmpfd, 'w')
  6465.                             ppdfile.write(ppdcontent)
  6466.                             ppdfile.close()
  6467.                             ppd = cups.PPD(ppdname)
  6468.                             os.unlink(ppdname)
  6469.  
  6470.         except RuntimeError, e:
  6471.             debugprint ("RuntimeError: " + str(e))
  6472.             if self.rbtnNPFoomatic.get_active():
  6473.                 # Foomatic database problem of some sort.
  6474.                 err_title = _('Database error')
  6475.                 err_text = _("The '%s' driver cannot be "
  6476.                              "used with printer '%s %s'.")
  6477.                 model, iter = (self.tvNPDrivers.get_selection().
  6478.                                get_selected())
  6479.                 nr = model.get_path(iter)[0]
  6480.                 driver = self.NPDrivers[nr]
  6481.                 if driver.startswith ("gutenprint"):
  6482.                     # This printer references some XML that is not
  6483.                     # installed by default.  Point the user at the
  6484.                     # package they need to install.
  6485.                     err = _("You will need to install the '%s' package "
  6486.                             "in order to use this driver.") % \
  6487.                             "gutenprint-foomatic"
  6488.                 else:
  6489.                     err = err_text % (driver, self.NPMake, self.NPModel)
  6490.             elif self.rbtnNPPPD.get_active():
  6491.                 # This error came from trying to open the PPD file.
  6492.                 err_title = _('PPD error')
  6493.                 filename = self.filechooserPPD.get_filename()
  6494.                 err = _('Failed to read PPD file.  Possible reason '
  6495.                         'follows:') + '\n'
  6496.                 try:
  6497.                     # We want this to be in the current natural language,
  6498.                     # so we intentionally don't set LC_ALL=C here.
  6499.                     p = subprocess.Popen (['/usr/bin/cupstestppd',
  6500.                                            '-rvv', filename],
  6501.                                           stdin=file("/dev/null"),
  6502.                                           stdout=subprocess.PIPE,
  6503.                                           stderr=subprocess.PIPE)
  6504.                     (stdout, stderr) = p.communicate ()
  6505.                     err += stdout
  6506.                 except:
  6507.                     # Problem executing command.
  6508.                     raise
  6509.             else:
  6510.                 # Failed to get PPD downloaded from OpenPrinting XXX
  6511.                 err_title = _('Downloadable drivers')
  6512.                 err = _("Failed to download PPD.")
  6513.  
  6514.             show_error_dialog (err_title, err, self.NewPrinterWindow)
  6515.             return None
  6516.  
  6517.         debugprint("ppd: " + repr(ppd))
  6518.         if isinstance(ppd, str) or isinstance(ppd, unicode):
  6519.             self.mainapp.cups._begin_operation (_("fetching PPD"))
  6520.             try:
  6521.                 if ppd != "raw":
  6522.                     f = self.mainapp.cups.getServerPPD(ppd)
  6523.                     ppd = cups.PPD(f)
  6524.                     os.unlink(f)
  6525.             except RuntimeError:
  6526.                 nonfatalException()
  6527.                 debugprint ("libcups from CUPS 1.3 not available: never mind")
  6528.             except cups.IPPError:
  6529.                 nonfatalException()
  6530.                 debugprint ("CUPS 1.3 server not available: never mind")
  6531.  
  6532.             self.mainapp.cups._end_operation ()
  6533.  
  6534.         return ppd
  6535.  
  6536.     # Installable Options
  6537.  
  6538.     def fillNPInstallableOptions(self):
  6539.         debugprint ("Examining installable options")
  6540.         self.installable_options = False
  6541.         self.options = { }
  6542.  
  6543.         container = self.vbNPInstallOptions
  6544.         for child in container.get_children():
  6545.             container.remove(child)
  6546.  
  6547.         if not self.ppd:
  6548.             l = gtk.Label(_("No Installable Options"))
  6549.             container.add(l)
  6550.             l.show()
  6551.             debugprint ("No PPD so no installable options")
  6552.             return
  6553.  
  6554.         # build option tabs
  6555.         for group in self.ppd.optionGroups:
  6556.             if group.name != "InstallableOptions":
  6557.                 continue
  6558.             self.installable_options = True
  6559.  
  6560.             table = gtk.Table(1, 3, False)
  6561.             table.set_col_spacings(6)
  6562.             table.set_row_spacings(6)
  6563.             container.add(table)
  6564.             rows = 0
  6565.  
  6566.             for nr, option in enumerate(group.options):
  6567.                 if option.keyword == "PageRegion":
  6568.                     continue
  6569.                 rows += 1
  6570.                 table.resize (rows, 3)
  6571.                 o = OptionWidget(option, self.ppd, self)
  6572.                 table.attach(o.conflictIcon, 0, 1, nr, nr+1, 0, 0, 0, 0)
  6573.  
  6574.                 hbox = gtk.HBox()
  6575.                 if o.label:
  6576.                     a = gtk.Alignment (0.5, 0.5, 1.0, 1.0)
  6577.                     a.set_padding (0, 0, 0, 6)
  6578.                     a.add (o.label)
  6579.                     table.attach(a, 1, 2, nr, nr+1, gtk.FILL, 0, 0, 0)
  6580.                     table.attach(hbox, 2, 3, nr, nr+1, gtk.FILL, 0, 0, 0)
  6581.                 else:
  6582.                     table.attach(hbox, 1, 3, nr, nr+1, gtk.FILL, 0, 0, 0)
  6583.                 hbox.pack_start(o.selector, False)
  6584.                 self.options[option.keyword] = o
  6585.         if not self.installable_options:
  6586.             l = gtk.Label(_("No Installable Options"))
  6587.             container.add(l)
  6588.             l.show()
  6589.         self.scrNPInstallableOptions.hide()
  6590.         self.scrNPInstallableOptions.show_all()
  6591.  
  6592.  
  6593.     # Create new Printer
  6594.     def on_btnNPApply_clicked(self, widget):
  6595.         if self.dialog_mode in ("class", "printer", "printer_with_uri"):
  6596.             name = unicode (self.entNPName.get_text())
  6597.             location = unicode (self.entNPLocation.get_text())
  6598.             info = unicode (self.entNPDescription.get_text())
  6599.         else:
  6600.             name = self.mainapp.printer.name
  6601.  
  6602.         # Whether to check for missing drivers.
  6603.         check = False
  6604.         checkppd = None
  6605.         ppd = self.ppd
  6606.  
  6607.         if self.dialog_mode == "class":
  6608.             members = getCurrentClassMembers(self.tvNCMembers)
  6609.             try:
  6610.                 for member in members:
  6611.                     self.mainapp.cups.addPrinterToClass(member, name)
  6612.             except cups.IPPError, (e, msg):
  6613.                 self.show_IPP_Error(e, msg)
  6614.                 return
  6615.         elif self.dialog_mode == "printer" or \
  6616.                 self.dialog_mode == "printer_with_uri":
  6617.             uri = None
  6618.             if self.device.uri:
  6619.                 uri = self.device.uri
  6620.             else:
  6621.                 uri = self.getDeviceURI()
  6622.             if not self.ppd: # XXX needed?
  6623.                 # Go back to previous page to re-select driver.
  6624.                 self.nextNPTab(-1)
  6625.                 return
  6626.  
  6627.             # write Installable Options to ppd
  6628.             for option in self.options.itervalues():
  6629.                 option.writeback()
  6630.  
  6631.             self.busy (self.NewPrinterWindow)
  6632.             while gtk.events_pending ():
  6633.                 gtk.main_iteration ()
  6634.             self.mainapp.cups._begin_operation (_("adding printer %s") % name)
  6635.             try:
  6636.                 if isinstance(ppd, str) or isinstance(ppd, unicode):
  6637.                     self.mainapp.cups.addPrinter(name, ppdname=ppd,
  6638.                          device=uri, info=info, location=location)
  6639.                     check = True
  6640.                 elif ppd is None: # raw queue
  6641.                     self.mainapp.cups.addPrinter(name, device=uri,
  6642.                                          info=info, location=location)
  6643.                 else:
  6644.                     cupshelpers.setPPDPageSize(ppd, self.language[0])
  6645.                     self.mainapp.cups.addPrinter(name, ppd=ppd,
  6646.                          device=uri, info=info, location=location)
  6647.                     check = True
  6648.                     checkppd = ppd
  6649.             except cups.IPPError, (e, msg):
  6650.                 self.ready (self.NewPrinterWindow)
  6651.                 self.show_IPP_Error(e, msg)
  6652.                 self.mainapp.cups._end_operation()
  6653.                 return
  6654.             except:
  6655.                 self.ready (self.NewPrinterWindow)
  6656.                 self.mainapp.cups._end_operation()
  6657.                 fatalException (1)
  6658.             self.mainapp.cups._end_operation()
  6659.             self.ready (self.NewPrinterWindow)
  6660.         if self.dialog_mode in ("class", "printer", "printer_with_uri"):
  6661.             self.mainapp.cups._begin_operation (_("modifying printer %s") %
  6662.                                                 name)
  6663.             try:
  6664.                 cupshelpers.activateNewPrinter (self.mainapp.cups, name)
  6665.                 self.mainapp.cups.setPrinterLocation(name, location)
  6666.                 self.mainapp.cups.setPrinterInfo(name, info)
  6667.             except cups.IPPError, (e, msg):
  6668.                 self.show_IPP_Error(e, msg)
  6669.                 self.mainapp.cups._end_operation ()
  6670.                 return
  6671.             self.mainapp.cups._end_operation ()
  6672.         elif self.dialog_mode == "device":
  6673.             self.mainapp.cups._begin_operation (_("modifying printer %s") %
  6674.                                                 name)
  6675.             try:
  6676.                 uri = self.getDeviceURI()
  6677.                 if not self.install_hplip_plugin(uri):
  6678.                     self.on_NPCancel(None)
  6679.                     return
  6680.  
  6681.                 self.mainapp.cups.addPrinter(name, device=uri)
  6682.             except cups.IPPError, (e, msg):
  6683.                 self.show_IPP_Error(e, msg)
  6684.                 self.mainapp.cups._end_operation ()
  6685.                 return
  6686.             self.mainapp.cups._end_operation ()
  6687.         elif self.dialog_mode == "ppd":
  6688.             if not ppd:
  6689.                 ppd = self.ppd = self.getNPPPD()
  6690.                 if not ppd:
  6691.                     # Go back to previous page to re-select driver.
  6692.                     self.nextNPTab(-1)
  6693.                     return
  6694.  
  6695.             self.mainapp.cups._begin_operation (_("modifying printer %s") %
  6696.                                                 name)
  6697.             # set ppd on server and retrieve it
  6698.             # cups doesn't offer a way to just download a ppd ;(=
  6699.             raw = False
  6700.             if isinstance(ppd, str) or isinstance(ppd, unicode):
  6701.                 if self.rbtnChangePPDasIs.get_active():
  6702.                     # To use the PPD as-is we need to prevent CUPS copying
  6703.                     # the old options over.  Do this by setting it to a
  6704.                     # raw queue (no PPD) first.
  6705.                     try:
  6706.                         self.mainapp.cups.addPrinter(name, ppdname='raw')
  6707.                     except cups.IPPError, (e, msg):
  6708.                         self.show_IPP_Error(e, msg)
  6709.                 try:
  6710.                     self.mainapp.cups.addPrinter(name, ppdname=ppd)
  6711.                 except cups.IPPError, (e, msg):
  6712.                     self.show_IPP_Error(e, msg)
  6713.                     self.mainapp.cups._end_operation ()
  6714.                     return
  6715.  
  6716.                 try:
  6717.                     filename = self.mainapp.cups.getPPD(name)
  6718.                     ppd = cups.PPD(filename)
  6719.                     os.unlink(filename)
  6720.                 except cups.IPPError, (e, msg):
  6721.                     if e == cups.IPP_NOT_FOUND:
  6722.                         raw = True
  6723.                     else:
  6724.                         self.show_IPP_Error(e, msg)
  6725.                         self.mainapp.cups._end_operation ()
  6726.                         return
  6727.             else:
  6728.                 # We have an actual PPD to upload, not just a name.
  6729.                 if ((not self.rbtnChangePPDasIs.get_active()) and
  6730.                     isinstance (self.mainapp.ppd, cups.PPD)):
  6731.                     cupshelpers.copyPPDOptions(self.mainapp.ppd, ppd)
  6732.                 else:
  6733.                     # write Installable Options to ppd
  6734.                     for option in self.options.itervalues():
  6735.                         option.writeback()
  6736.                     cupshelpers.setPPDPageSize(ppd, self.language[0])
  6737.  
  6738.                 try:
  6739.                     self.mainapp.cups.addPrinter(name, ppd=ppd)
  6740.                 except cups.IPPError, (e, msg):
  6741.                     self.show_IPP_Error(e, msg)
  6742.  
  6743.             self.mainapp.cups._end_operation ()
  6744.  
  6745.             if not raw:
  6746.                 check = True
  6747.                 checkppd = ppd
  6748.  
  6749.         self.NewPrinterWindow.hide()
  6750.         self.mainapp.populateList()
  6751.  
  6752.         # Now select it.
  6753.         dests_iconview = self.mainapp.dests_iconview
  6754.         model = dests_iconview.get_model ()
  6755.         iter = model.get_iter_first ()
  6756.         while iter != None:
  6757.             queue = unicode (model.get_value (iter, 2))
  6758.             if queue == name:
  6759.                 path = model.get_path (iter)
  6760.                 dests_iconview.scroll_to_path (path, True, 0.5, 0.5)
  6761.                 dests_iconview.unselect_all ()
  6762.                 dests_iconview.set_cursor (path)
  6763.                 dests_iconview.select_path (path)
  6764.                 break
  6765.  
  6766.             iter = model.iter_next (iter)
  6767.  
  6768.         # Load information about the printer,
  6769.         # e.g. self.mainapp.server_side_options and self.mainapp.ppd
  6770.         # (both used below).
  6771.         self.mainapp.fillPrinterTab (name)
  6772.  
  6773.         # Select 'Settings' in the properties treeview.
  6774.         self.mainapp.tvPrinterProperties.set_cursor ((0,))
  6775.  
  6776.         if check:
  6777.             try:
  6778.                 self.checkDriverExists (name, ppd=checkppd)
  6779.             except:
  6780.                 nonfatalException()
  6781.  
  6782.             # Also check to see whether the media option has become
  6783.             # invalid.  This can happen if it had previously been
  6784.             # explicitly set to a page size that is not offered with
  6785.             # the new PPD (see bug #441836).
  6786.             try:
  6787.                 option = self.mainapp.server_side_options['media']
  6788.                 if option.get_current_value () == None:
  6789.                     debugprint ("Invalid media option: resetting")
  6790.                     option.reset ()
  6791.                     self.mainapp.changed.add (option)
  6792.                     self.mainapp.save_printer (self.mainapp.printer)
  6793.             except KeyError:
  6794.                 pass
  6795.             except:
  6796.                 nonfatalException()
  6797.  
  6798.         # Finally, suggest printing a test page.
  6799.         if (self.dialog_mode == "printer" or \
  6800.             self.dialog_mode == "printer_with_uri") and \
  6801.             self.mainapp.ppd != False:
  6802.             q = gtk.MessageDialog (self.mainapp.PrintersWindow,
  6803.                                    gtk.DIALOG_DESTROY_WITH_PARENT |
  6804.                                    gtk.DIALOG_MODAL,
  6805.                                    gtk.MESSAGE_QUESTION,
  6806.                                    gtk.BUTTONS_YES_NO,
  6807.                                    _("Would you like to print a test page?"))
  6808.             response = q.run ()
  6809.             q.destroy ()
  6810.             if response == gtk.RESPONSE_YES:
  6811.                 # Load the printer details but hide the properties dialog.
  6812.                 self.mainapp.display_properties_dialog_for (name)
  6813.                 self.mainapp.PrinterPropertiesDialog.hide ()
  6814.  
  6815.                 # Click the test button.
  6816.                 self.mainapp.btnPrintTestPage.clicked ()
  6817.  
  6818.     def checkDriverExists(self, name, ppd=None):
  6819.         """Check that the driver for an existing queue actually
  6820.         exists, and prompt to install the appropriate package
  6821.         if not.
  6822.  
  6823.         ppd: cups.PPD object, if already created"""
  6824.  
  6825.         # Is this queue on the local machine?  If not, we can't check
  6826.         # anything at all.
  6827.         server = cups.getServer ()
  6828.         if not (server == 'localhost' or server == '127.0.0.1' or
  6829.                 server == '::1' or server[0] == '/'):
  6830.             return
  6831.  
  6832.         # Fetch the PPD if we haven't already.
  6833.         if not ppd:
  6834.             try:
  6835.                 filename = self.mainapp.cups.getPPD(name)
  6836.             except cups.IPPError, (e, msg):
  6837.                 if e == cups.IPP_NOT_FOUND:
  6838.                     # This is a raw queue.  Nothing to check.
  6839.                     return
  6840.                 else:
  6841.                     self.show_IPP_Error(e, msg)
  6842.                     return
  6843.  
  6844.             ppd = cups.PPD(filename)
  6845.             os.unlink(filename)
  6846.  
  6847.         (pkgs, exes) = cupshelpers.missingPackagesAndExecutables (ppd)
  6848.         if len (pkgs) > 0 or len (exes) > 0:
  6849.             # We didn't find a necessary executable.  Complain.
  6850.             can_install = False
  6851.             if len (pkgs) > 0:
  6852.                 try:
  6853.                     pk = installpackage.PackageKit ()
  6854.                     can_install = True
  6855.                 except:
  6856.                     pass
  6857.  
  6858.             if can_install and len (pkgs) > 0:
  6859.                 pkg = pkgs[0]
  6860.                 install_text = ('<span weight="bold" size="larger">' +
  6861.                                 _('Install driver') + '</span>\n\n' +
  6862.                                 _("Printer '%s' requires the %s package but "
  6863.                                   "it is not currently installed.") %
  6864.                                 (name, pkg))
  6865.                 dialog = self.InstallDialog
  6866.                 self.lblInstall.set_markup(install_text)
  6867.                 dialog.set_transient_for (self.mainapp.PrintersWindow)
  6868.                 response = dialog.run ()
  6869.                 dialog.hide ()
  6870.                 if response == gtk.RESPONSE_OK:
  6871.                     # Install the package.
  6872.                     try:
  6873.                         xid = self.mainapp.PrintersWindow.window.xid
  6874.                         pk.InstallPackageName (xid, 0, pkg)
  6875.                     except:
  6876.                         pass # should handle error
  6877.             else:
  6878.                 show_error_dialog (_('Missing driver'),
  6879.                                    _("Printer '%s' requires the '%s' program "
  6880.                                      "but it is not currently installed.  "
  6881.                                      "Please install it before using this "
  6882.                                      "printer.") % (name, (exes + pkgs)[0]),
  6883.                                    self.mainapp.PrintersWindow)
  6884.  
  6885.  
  6886. def main(setup_printer = None, configure_printer = None, change_ppd = False,
  6887.          devid = "", print_test_page = False, focus_on_map = True):
  6888.     cups.setUser (os.environ.get ("CUPS_USER", cups.getUser()))
  6889.     gtk.gdk.threads_init()
  6890.  
  6891.     mainwindow = GUI(setup_printer, configure_printer, change_ppd, devid,
  6892.                      print_test_page, focus_on_map)
  6893.  
  6894.     if gtk.__dict__.has_key("main"):
  6895.         gtk.main()
  6896.     else:
  6897.         gtk.mainloop()
  6898.  
  6899.  
  6900. if __name__ == "__main__":
  6901.     import getopt
  6902.     try:
  6903.         opts, args = getopt.gnu_getopt (sys.argv[1:], '',
  6904.                                         ['setup-printer=',
  6905.                                          'configure-printer=',
  6906.                                          'choose-driver=',
  6907.                                          'devid=',
  6908.                                          'print-test-page=',
  6909.                                          'no-focus-on-map',
  6910.                                          'debug'])
  6911.     except getopt.GetoptError:
  6912.         show_help ()
  6913.         sys.exit (1)
  6914.  
  6915.     setup_printer = None
  6916.     configure_printer = None
  6917.     change_ppd = False
  6918.     print_test_page = False
  6919.     focus_on_map = True
  6920.     devid = ""
  6921.     for opt, optarg in opts:
  6922.         if (opt == "--configure-printer" or
  6923.             opt == "--choose-driver" or
  6924.             opt == "--print-test-page"):
  6925.             configure_printer = optarg
  6926.             if opt == "--choose-driver":
  6927.                 change_ppd = True
  6928.             elif opt == "--print-test-page":
  6929.                 print_test_page = True
  6930.  
  6931.         elif opt == '--setup-printer':
  6932.             setup_printer = optarg
  6933.  
  6934.         elif opt == '--devid':
  6935.             devid = optarg
  6936.  
  6937.         elif opt == '--no-focus-on-map':
  6938.             focus_on_map = False
  6939.  
  6940.         elif opt == '--debug':
  6941.             set_debugging (True)
  6942.  
  6943.     main(setup_printer, configure_printer, change_ppd, devid, print_test_page,
  6944.          focus_on_map)
  6945.